diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c1aa0cff5..357d62bd56 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,63 @@
# SQLCipher Change Log
-All notable changes to this project will be documented in this file.
+Notable changes to this project are documented in this file.
+
+## [unreleased] - (? 2025 - [unreleased changes])
+
+## [4.9.0] - (May 2025 - [4.9.0 changes])
+- Updates baseline to upstream SQLite 3.46.2
+- Removes use of static mutex in `sqlcipher_extra_shutdown()`
+
+## [4.8.0] - (April 2025 - [4.8.0 changes])
+- Fixes regression in `PRAGMA cipher_migrate` where an error would be thrown when migrating a current-version database
+- Adds selective locking in critical sections of the library for shared cache connections (Note: use of shared cache is still strongly discouraged)
+- Standardizes initial private heap size to 48KB to ensure mlock under constrained limits
+- Removes changes to windows working set sizes
+- Improvements to logging of memory stats and other cleanup
+
+## [4.7.0] - (March 2025 - [4.7.0 changes])
+- Updates baseline to upstream SQLite 3.49.1, including complete upstream SQLite refactoring of build system to use autosetup
+- Significantly refactors and optimizes library initialization and cleanup
+- Allocates majority of requisite memory at startup to improve memory locking on constrained platforms (i.e. Android and Windows) and reduce fragmentation
+- Expands `sqlcipher_provider` interface to include `init` and `shutdown` functions
+- Adds support for `.recover` shell command on corrupt databases with a full plaintext first page
+- Performs fast random overwrite of freed memory segments for improved security
+- Adds basic obfuscation of context key material for improved security
+- Generates keyspecs dynamically on demand instead of storing them
+- Expands keyspec/raw key format to accept key, HMAC key, and salt
+- Improves error handling in `sqlcipher_export()` and `PRAGMA cipher_migrate`
+- Allows setting custom compile-time default cryptographic provider via the `SQLCIPHER_CRYPTO_CUSTOM` macro
+- Removes support for end-of-life OpenSSL versions older than 3.0
+__BREAKING CHANGE__: `SELECT` statements (now also including schema independent queries like `SELECT 1`) cannot be executed on encrypt ed databases prior to setting the database key (behavior inherited from upstream SQLite)
+- __BREAKING CHANGE__: Renames `configure` flag `--enable-tempstore=yes` to `--with-tempstore=yes` for alignment with SQLite (change required for upstream SQLite autosetup)
+- __BREAKING CHANGE__: Renames default executable and library build outputs from `sqlcipher` and `libsqlcipher` to `sqlite3` and `libsqlite3` (for alignment with SQLite)
+- __BREAKING CHANGE__: Removes `configure` flag `--with-crypto-lib` (replace with appropriate `-DSQLCIPHER_CRYPTO_*` CFLAG)
+- __BREAKING CHANGE__: Requires defining `SQLITE_EXTRA_INIT=sqlcipher_extra_init` and `SQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown` at compile time for optimized library initialization and cleanup
+- __BREAKING CHANGE__: Enforces thread safe mode (i.e. `SQLITE_THREADSAFE` of 1 or 2) and temporary storage (i.e. `SQLITE_TEMP_STORE` of 2 or 3) settings at compile time
+
+## [4.6.1] - (August 2024 - [4.6.1 changes])
+- Updates baseline to upstream SQLite 3.46.1
+- Significant refactor to merge `crypto.h`, `crypto.c`, and `crypto_impl.c` into a single `sqlcipher.c` source file for simplicity.
+- Updates minimum working set size on windows to increase lockable pages
+- Adds new `PRAGMA cipher_log_source` for filtering log output on higher verbosity levels
+- Improves log output by including the log level and source prior to message
+- Improves error logging in `PRAGMA cipher_migrate`
+- Fixes issue where log level and target would be overwritten if set prior to initialization
+- Corrects Podspec license element to use specific BSD 3 Clause
+- Fixes default log output to console for macOS
+
+## [4.6.0] - (May 2024 - [4.6.0 changes])
+- Sets default log level to WARN
+- Sends default log output to: logcat for Android; Console for iOS and macOS; and stderr for all other platforms
+- General improvements to log level assignments, output, and sanitization
+- Fixes Apple Privacy Manifest by removing empty NSPrivacyCollectedDataType from PrivacyInfo.xcprivacy
+- Moves Swift support defines for podspec user_target_xcconfig so they only apply to the consuming project
+
+## [4.5.7] - (April 2024 - [4.5.7 changes])
+- Updates baseline to upstream SQLite 3.45.3
+- Adds "device" logging and profile target using os_log for Apple (and logcat on Android)
+- Fixes issues compiling with SQLITE_OMIT_LOG
+- fixes malformed man page caused by old merge conflict
+- Updates podspec for current Xcode versions, improved Swift support, and Privacy Manifest
## [4.5.6] - (January 2024 - [4.5.6 changes])
- Updates baseline to upstream SQLite 3.44.2
@@ -232,6 +290,20 @@ All notable changes to this project will be documented in this file.
### Security
- Change KDF iteration length from 4,000 to 64,000
+[unreleased]: https://github.com/sqlcipher/sqlcipher/tree/prerelease
+[unreleased changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.8.0...prerelease
+[4.9.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.9.0
+[4.9.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.8.0...v4.9.0
+[4.8.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.8.0
+[4.8.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.7.0...v4.8.0
+[4.7.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.7.0
+[4.7.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.6.1...v4.7.0
+[4.6.1]: https://github.com/sqlcipher/sqlcipher/tree/v4.6.1
+[4.6.1 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.6.0...v4.6.1
+[4.6.0]: https://github.com/sqlcipher/sqlcipher/tree/v4.6.0
+[4.6.0 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.5.7...v4.6.0
+[4.5.7]: https://github.com/sqlcipher/sqlcipher/tree/v4.5.7
+[4.5.7 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.5.6...v4.5.7
[4.5.6]: https://github.com/sqlcipher/sqlcipher/tree/v4.5.6
[4.5.6 changes]: https://github.com/sqlcipher/sqlcipher/compare/v4.5.5...v4.5.6
[4.5.5]: https://github.com/sqlcipher/sqlcipher/tree/v4.5.5
diff --git a/LICENSE.md b/LICENSE.md
index 7167addca1..3f71443161 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,4 +1,4 @@
-Copyright (c) 2008-2023, ZETETIC LLC
+Copyright (c) 2025, ZETETIC LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000000..3f71443161
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2025, ZETETIC LLC
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the ZETETIC LLC nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Makefile.in b/Makefile.in
index 870c5d301e..60cc228e9b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,1640 +1,305 @@
-#!/usr/make
+#!/usr/bin/make
+# ^^^^ help out editors which guess this file's type.
#
# Makefile for SQLITE
#
-# This makefile is suppose to be configured automatically using the
-# autoconf. But if that does not work for you, you can configure
-# the makefile manually. Just set the parameters below to values that
-# work well for your system.
+# This makefile is intended to be configured automatically using the
+# configure script.
#
-# If the configure script does not work out-of-the-box, you might
-# be able to get it to work by giving it some hints. See the comment
-# at the beginning of configure.in for additional information.
+# The docs for many of its variables are in the primary static
+# makefile, main.mk (which this one includes at runtime).
#
-
-# The toplevel directory of the source tree. This is the directory
-# that contains this "Makefile.in" and the "configure.in" script.
+all:
+########################################################################
#
-TOP = @abs_srcdir@
-
-
-# C Compiler and options for use in building executables that
-# will run on the platform that is doing the build.
+# Known TODOs/FIXMEs/TOIMPROVEs for the autosetup port, in no
+# particular order...
#
-BCC = @BUILD_CC@ @BUILD_CFLAGS@
-
-# TCC is the C Compile and options for use in building executables that
-# will run on the target platform. (BCC and TCC are usually the
-# same unless your are cross-compiling.) Separate CC and CFLAGS macros
-# are provide so that these aspects of the build process can be changed
-# on the "make" command-line. Ex: "make CC=clang CFLAGS=-fsanitize=undefined"
+# - TEA pieces.
#
-CC = @CC@
-CFLAGS = @CPPFLAGS@ @CFLAGS@
-TCC = ${CC} ${CFLAGS} -I. -I${TOP}/src -I${TOP}/ext/rtree -I${TOP}/ext/icu
-TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session
-TCC += -I${TOP}/ext/userauth
-
-# Define this for the autoconf-based build, so that the code knows it can
-# include the generated sqlite_cfg.h
+# - Replace the autotools-specific distribution deliverable(s).
#
-TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
-
-# Define -DNDEBUG to compile without debugging (i.e., for production usage)
-# Omitting the define will cause extra debugging code to be inserted and
-# includes extra comments when "EXPLAIN stmt" is used.
+# - Confirm whether cross-compilation works and patch it
+# appropriately.
#
-TCC += @TARGET_DEBUG@
-
-# Compiler options needed for programs that use the TCL library.
+# Maintenance reminders:
#
-TCC += @TCL_INCLUDE_SPEC@
-
-# The library that programs using TCL must link against.
+# - This makefile should remain as POSIX-make-compatible as possible:
+# https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html
#
-LIBTCL = @TCL_LIB_SPEC@
-
-# Compiler options needed for programs that use the readline() library.
+# - The naming convention of some vars, using periods instead of
+# underscores, though unconventional, was selected for a couple of
+# reasons: 1) Personal taste (for which there is no accounting). 2)
+# It is thought to help defend against inadvertent injection of
+# those vars via environment variables (because X.Y is not a legal
+# environment variable name). "Feature or bug?" is debatable and
+# this naming convention may be reverted if it causes any grief.
#
-READLINE_FLAGS = -DHAVE_READLINE=@TARGET_HAVE_READLINE@ @TARGET_READLINE_INC@
-READLINE_FLAGS += -DHAVE_EDITLINE=@TARGET_HAVE_EDITLINE@
-READLINE_FLAGS += -DHAVE_LINENOISE=@TARGET_HAVE_LINENOISE@
-# The library that programs using readline() must link against.
#
-LIBREADLINE = @TARGET_READLINE_LIBS@
-
-# Should the database engine be compiled threadsafe
+# The top-most directory of the source tree. This is the directory
+# that contains this "Makefile.in" and the "configure" script.
#
-TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@
+TOP = @abs_top_srcdir@
-# Any target libraries which libsqlite must be linked against
#
-TLIBS = @LIBS@ $(LIBS)
-
-# Flags controlling use of the in memory btree implementation
+# Autotools-conventional vars which are used by package installation
+# rules in main.mk. To get sane handling when a user overrides only
+# a subset of these, we perform some acrobatics with these vars
+# in the configure script: see [proj-remap-autoconf-dir-vars] for
+# full details.
#
-# SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
-# default to file, 2 to default to memory, and 3 to force temporary
-# tables to always be in memory.
+# For completeness's sake, the aforementioned conventional vars which
+# are relevant to our installation rules are:
#
-TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@
-
-# Enable/disable loadable extensions, and other optional features
-# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
-# The same set of OMIT and ENABLE flags should be passed to the
-# LEMON parser generator and the mkkeywordhash tool as well.
-OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
-
-TCC += $(OPT_FEATURE_FLAGS)
-
-# Add in any optional parameters specified on the make commane line
-# ie. make "OPTS=-DSQLITE_ENABLE_FOO=1 -DSQLITE_OMIT_FOO=1".
-TCC += $(OPTS)
-
-# Add in compile-time options for some libraries used by extensions
-TCC += @HAVE_ZLIB@
-
-# Version numbers and release number for the SQLite being compiled.
+# datadir = $(prefix)/share
+# mandir = $(datadir)/man
+# includedir = $(prefix)/include
+# exec_prefix = $(prefix)
+# bindir = $(exec_prefix)/bin
+# libdir = $(exec_prefix)/lib
#
-VERSION = @VERSION@
-VERSION_NUMBER = @VERSION_NUMBER@
-RELEASE = @RELEASE@
-
-# Filename extensions
+# Our builds do not require any of their relatives:
#
-BEXE = @BUILD_EXEEXT@
-TEXE = @TARGET_EXEEXT@
-
-# The following variable is "1" if the configure script was able to locate
-# the tclConfig.sh file. It is an empty string otherwise. When this
-# variable is "1", the TCL extension library (libtclsqlite3.so) is built
-# and installed.
+# sbindir = $(exec_prefix)/sbin
+# sysconfdir = /etc
+# sharedstatedir = $(prefix)/com
+# localstatedir = /var
+# runstatedir = /run
+# infodir = $(datadir)/info
+# libexecdir = $(exec_prefix)/libexec
#
-HAVE_TCL = @HAVE_TCL@
+prefix = @prefix@
+datadir = @datadir@
+mandir = @mandir@
+includedir = @includedir@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
-# This is the command to use for tclsh - normally just "tclsh", but we may
-# know the specific version we want to use
+INSTALL = @BIN_INSTALL@
+AR = @AR@
+AR.flags = cr
+CC = @CC@
+B.cc = @CC_FOR_BUILD@ @BUILD_CFLAGS@
+T.cc = $(CC)
#
-TCLSH_CMD = @TCLSH_CMD@
-
-# Where do we want to install the tcl plugin
+# $(CFLAGS) is problematic because it is frequently overridden when
+# invoking make, which loses things like -fPIC. So... we avoid using
+# it directly and instead add a level of indirection. We combine
+# $(CFLAGS) and $(CPPFLAGS) here because that's the way the legacy
+# build did it and many builds rely on that. See main.mk for more
+# details.
#
-TCLLIBDIR = @TCLLIBDIR@
-
-# The suffix used on shared libraries. Ex: ".dll", ".so", ".dylib"
+# Historical note: the pre-3.48 build only honored CPPFLAGS at
+# configure-time, and expanded them into the generated Makefile. There
+# are, in that build, no uses of CPPFLAGS in the configure-expanded
+# Makefile. Ergo: if a client configures with CPPFLAGS=... and then
+# explicitly passes CFLAGS=... to make, the CPPFLAGS will be
+# lost. That behavior is retained in 3.48+.
#
-SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@
-
-# If gcov support was enabled by the configure script, add the appropriate
-# flags here. It's not always as easy as just having the user add the right
-# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
-# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
-# Supposedly GCC does the right thing if you use --coverage, but in
-# practice it still fails. See:
+CFLAGS = @CFLAGS@ @CPPFLAGS@
#
-# http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html
+# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
+# configure. See main.mk.
#
-# for more info.
-#
-GCOV_CFLAGS1 = -DSQLITE_COVERAGE_TEST=1 -fprofile-arcs -ftest-coverage
-GCOV_LDFLAGS1 = -lgcov
-USE_GCOV = @USE_GCOV@
-LTCOMPILE_EXTRAS += $(GCOV_CFLAGS$(USE_GCOV))
-LTLINK_EXTRAS += $(GCOV_LDFLAGS$(USE_GCOV))
-
-# BEGIN CRYPTO
-CRYPTOLIBOBJ = \
- crypto.lo \
- crypto_impl.lo \
- crypto_openssl.lo \
- crypto_libtomcrypt.lo \
- crypto_nss.lo \
- crypto_cc.lo
-
-CRYPTOSRC = \
- $(TOP)/src/crypto.h \
- $(TOP)/src/sqlcipher.h \
- $(TOP)/src/crypto.c \
- $(TOP)/src/crypto_impl.c \
- $(TOP)/src/crypto_libtomcrypt.c \
- $(TOP)/src/crypto_nss.c \
- $(TOP)/src/crypto_openssl.c \
- $(TOP)/src/crypto_cc.c
+LDFLAGS.configure = @LDFLAGS@
-# END CRYPTO
-
-# The directory into which to store package information for
-
-# Some standard variables and programs
#
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-libdir = @libdir@
-pkgconfigdir = $(libdir)/pkgconfig
-bindir = @bindir@
-includedir = @includedir@/sqlcipher
-INSTALL = @INSTALL@
-LIBTOOL = ./libtool
-ALLOWRELEASE = @ALLOWRELEASE@
-
-# libtool compile/link/install
-LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(TCC) $(LTCOMPILE_EXTRAS)
-LTLINK = $(LIBTOOL) --mode=link $(TCC) $(LTCOMPILE_EXTRAS) @LDFLAGS@ $(LTLINK_EXTRAS)
-LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
-
-# You should not have to change anything below this line
-###############################################################################
+# CFLAGS.core is documented in main.mk.
+#
+CFLAGS.core = @SH_CFLAGS@
+LDFLAGS.shlib = @SH_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+LDFLAGS.rpath = @LDFLAGS_RPATH@
+LDFLAGS.pthread = @LDFLAGS_PTHREAD@
+LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
+LDFLAGS.readline = @LDFLAGS_READLINE@
+CFLAGS.readline = @CFLAGS_READLINE@
+LDFLAGS.icu = @LDFLAGS_ICU@
+LDFLAGS.rt = @LDFLAGS_RT@
+CFLAGS.icu = @CFLAGS_ICU@
+LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
+# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific = \
+ @LDFLAGS_MAC_CVERSION@ @LDFLAGS_MAC_INSTALL_NAME@ @LDFLAGS_OUT_IMPLIB@
+# os-specific: see
+# - https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7
+# - https://sqlite.org/forum/forumpost/0c7fc097b2
+# - https://sqlite.org/forum/forumpost/5651662b8875ec0a
-USE_AMALGAMATION = @USE_AMALGAMATION@
-AMALGAMATION_LINE_MACROS = @AMALGAMATION_LINE_MACROS@
+libsqlite3.DLL.basename = @SQLITE_DLL_BASENAME@
+# DLL.basename: see https://sqlite.org/forum/forumpost/828fdfe904
+libsqlite3.out.implib = @SQLITE_OUT_IMPLIB@
+# libsqlite3.out.implib => the output filename part of LDFLAGS_OUT_IMPLIB.
+ENABLE_LIB_SHARED = @ENABLE_LIB_SHARED@
+ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
+HAVE_WASI_SDK = @HAVE_WASI_SDK@
+libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
-# Object files for the SQLite library (non-amalgamation).
-#
-LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
- backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
- callback.lo complete.lo ctime.lo \
- date.lo dbpage.lo dbstat.lo delete.lo \
- expr.lo fault.lo fkey.lo \
- fts3.lo fts3_aux.lo fts3_expr.lo fts3_hash.lo fts3_icu.lo \
- fts3_porter.lo fts3_snippet.lo fts3_tokenizer.lo fts3_tokenizer1.lo \
- fts3_tokenize_vtab.lo \
- fts3_unicode.lo fts3_unicode2.lo fts3_write.lo \
- fts5.lo \
- func.lo global.lo hash.lo \
- icu.lo insert.lo json.lo legacy.lo loadext.lo \
- main.lo malloc.lo mem0.lo mem1.lo mem2.lo mem3.lo mem5.lo \
- memdb.lo memjournal.lo \
- mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
- notify.lo opcodes.lo os.lo os_kv.lo os_unix.lo os_win.lo \
- pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
- random.lo resolve.lo rowset.lo rtree.lo \
- sqlite3session.lo select.lo sqlite3rbu.lo status.lo stmt.lo \
- table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
- update.lo userauth.lo upsert.lo util.lo vacuum.lo \
- vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
- vdbetrace.lo vdbevtab.lo \
- wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
- window.lo utf.lo vtab.lo $(CRYPTOLIBOBJ)
+T.cc.sqlite = $(T.cc) @TARGET_DEBUG@
-# Object files for the amalgamation.
#
-LIBOBJS1 = sqlite3.lo
-
-# Determine the real value of LIBOBJ based on the 'configure' script
+# Define -D_HAVE_SQLITE_CONFIG_H so that the code knows it
+# can include the generated sqlite_cfg.h.
#
-LIBOBJ = $(LIBOBJS$(USE_AMALGAMATION))
-
-
-# All of the source code files.
-#
-SRC = \
- $(CRYPTOSRC) \
- $(TOP)/src/alter.c \
- $(TOP)/src/analyze.c \
- $(TOP)/src/attach.c \
- $(TOP)/src/auth.c \
- $(TOP)/src/backup.c \
- $(TOP)/src/bitvec.c \
- $(TOP)/src/btmutex.c \
- $(TOP)/src/btree.c \
- $(TOP)/src/btree.h \
- $(TOP)/src/btreeInt.h \
- $(TOP)/src/build.c \
- $(TOP)/src/callback.c \
- $(TOP)/src/complete.c \
- $(TOP)/src/ctime.c \
- $(TOP)/src/date.c \
- $(TOP)/src/dbpage.c \
- $(TOP)/src/dbstat.c \
- $(TOP)/src/delete.c \
- $(TOP)/src/expr.c \
- $(TOP)/src/fault.c \
- $(TOP)/src/fkey.c \
- $(TOP)/src/func.c \
- $(TOP)/src/global.c \
- $(TOP)/src/hash.c \
- $(TOP)/src/hash.h \
- $(TOP)/src/hwtime.h \
- $(TOP)/src/insert.c \
- $(TOP)/src/json.c \
- $(TOP)/src/legacy.c \
- $(TOP)/src/loadext.c \
- $(TOP)/src/main.c \
- $(TOP)/src/malloc.c \
- $(TOP)/src/mem0.c \
- $(TOP)/src/mem1.c \
- $(TOP)/src/mem2.c \
- $(TOP)/src/mem3.c \
- $(TOP)/src/mem5.c \
- $(TOP)/src/memdb.c \
- $(TOP)/src/memjournal.c \
- $(TOP)/src/msvc.h \
- $(TOP)/src/mutex.c \
- $(TOP)/src/mutex.h \
- $(TOP)/src/mutex_noop.c \
- $(TOP)/src/mutex_unix.c \
- $(TOP)/src/mutex_w32.c \
- $(TOP)/src/notify.c \
- $(TOP)/src/os.c \
- $(TOP)/src/os.h \
- $(TOP)/src/os_common.h \
- $(TOP)/src/os_setup.h \
- $(TOP)/src/os_kv.c \
- $(TOP)/src/os_unix.c \
- $(TOP)/src/os_win.c \
- $(TOP)/src/os_win.h \
- $(TOP)/src/pager.c \
- $(TOP)/src/pager.h \
- $(TOP)/src/parse.y \
- $(TOP)/src/pcache.c \
- $(TOP)/src/pcache.h \
- $(TOP)/src/pcache1.c \
- $(TOP)/src/pragma.c \
- $(TOP)/src/pragma.h \
- $(TOP)/src/prepare.c \
- $(TOP)/src/printf.c \
- $(TOP)/src/random.c \
- $(TOP)/src/resolve.c \
- $(TOP)/src/rowset.c \
- $(TOP)/src/select.c \
- $(TOP)/src/status.c \
- $(TOP)/src/shell.c.in \
- $(TOP)/src/sqlite.h.in \
- $(TOP)/src/sqlite3ext.h \
- $(TOP)/src/sqliteInt.h \
- $(TOP)/src/sqliteLimit.h \
- $(TOP)/src/table.c \
- $(TOP)/src/tclsqlite.c \
- $(TOP)/src/threads.c \
- $(TOP)/src/tokenize.c \
- $(TOP)/src/treeview.c \
- $(TOP)/src/trigger.c \
- $(TOP)/src/utf.c \
- $(TOP)/src/update.c \
- $(TOP)/src/upsert.c \
- $(TOP)/src/util.c \
- $(TOP)/src/vacuum.c \
- $(TOP)/src/vdbe.c \
- $(TOP)/src/vdbe.h \
- $(TOP)/src/vdbeapi.c \
- $(TOP)/src/vdbeaux.c \
- $(TOP)/src/vdbeblob.c \
- $(TOP)/src/vdbemem.c \
- $(TOP)/src/vdbesort.c \
- $(TOP)/src/vdbetrace.c \
- $(TOP)/src/vdbevtab.c \
- $(TOP)/src/vdbeInt.h \
- $(TOP)/src/vtab.c \
- $(TOP)/src/vxworks.h \
- $(TOP)/src/wal.c \
- $(TOP)/src/wal.h \
- $(TOP)/src/walker.c \
- $(TOP)/src/where.c \
- $(TOP)/src/wherecode.c \
- $(TOP)/src/whereexpr.c \
- $(TOP)/src/whereInt.h \
- $(TOP)/src/window.c
-
-# Source code for extensions
-#
-SRC += \
- $(TOP)/ext/fts3/fts3.c \
- $(TOP)/ext/fts3/fts3.h \
- $(TOP)/ext/fts3/fts3Int.h \
- $(TOP)/ext/fts3/fts3_aux.c \
- $(TOP)/ext/fts3/fts3_expr.c \
- $(TOP)/ext/fts3/fts3_hash.c \
- $(TOP)/ext/fts3/fts3_hash.h \
- $(TOP)/ext/fts3/fts3_icu.c \
- $(TOP)/ext/fts3/fts3_porter.c \
- $(TOP)/ext/fts3/fts3_snippet.c \
- $(TOP)/ext/fts3/fts3_tokenizer.h \
- $(TOP)/ext/fts3/fts3_tokenizer.c \
- $(TOP)/ext/fts3/fts3_tokenizer1.c \
- $(TOP)/ext/fts3/fts3_tokenize_vtab.c \
- $(TOP)/ext/fts3/fts3_unicode.c \
- $(TOP)/ext/fts3/fts3_unicode2.c \
- $(TOP)/ext/fts3/fts3_write.c
-SRC += \
- $(TOP)/ext/icu/sqliteicu.h \
- $(TOP)/ext/icu/icu.c
-SRC += \
- $(TOP)/ext/rtree/rtree.h \
- $(TOP)/ext/rtree/rtree.c \
- $(TOP)/ext/rtree/geopoly.c
-SRC += \
- $(TOP)/ext/session/sqlite3session.c \
- $(TOP)/ext/session/sqlite3session.h
-SRC += \
- $(TOP)/ext/userauth/userauth.c \
- $(TOP)/ext/userauth/sqlite3userauth.h
-SRC += \
- $(TOP)/ext/rbu/sqlite3rbu.h \
- $(TOP)/ext/rbu/sqlite3rbu.c
-SRC += \
- $(TOP)/ext/misc/stmt.c
-
-# Generated source code files
-#
-SRC += \
- keywordhash.h \
- opcodes.c \
- opcodes.h \
- parse.c \
- parse.h \
- sqlite_cfg.h \
- shell.c \
- sqlite3.h
-
-# Source code to the test files.
-#
-TESTSRC = \
- $(TOP)/src/test1.c \
- $(TOP)/src/test2.c \
- $(TOP)/src/test3.c \
- $(TOP)/src/test4.c \
- $(TOP)/src/test5.c \
- $(TOP)/src/test6.c \
- $(TOP)/src/test8.c \
- $(TOP)/src/test9.c \
- $(TOP)/src/test_autoext.c \
- $(TOP)/src/test_async.c \
- $(TOP)/src/test_backup.c \
- $(TOP)/src/test_bestindex.c \
- $(TOP)/src/test_blob.c \
- $(TOP)/src/test_btree.c \
- $(TOP)/src/test_config.c \
- $(TOP)/src/test_delete.c \
- $(TOP)/src/test_demovfs.c \
- $(TOP)/src/test_devsym.c \
- $(TOP)/src/test_fs.c \
- $(TOP)/src/test_func.c \
- $(TOP)/src/test_hexio.c \
- $(TOP)/src/test_init.c \
- $(TOP)/src/test_intarray.c \
- $(TOP)/src/test_journal.c \
- $(TOP)/src/test_malloc.c \
- $(TOP)/src/test_md5.c \
- $(TOP)/src/test_multiplex.c \
- $(TOP)/src/test_mutex.c \
- $(TOP)/src/test_onefile.c \
- $(TOP)/src/test_osinst.c \
- $(TOP)/src/test_pcache.c \
- $(TOP)/src/test_quota.c \
- $(TOP)/src/test_rtree.c \
- $(TOP)/src/test_schema.c \
- $(TOP)/src/test_superlock.c \
- $(TOP)/src/test_syscall.c \
- $(TOP)/src/test_tclsh.c \
- $(TOP)/src/test_tclvar.c \
- $(TOP)/src/test_thread.c \
- $(TOP)/src/test_vdbecov.c \
- $(TOP)/src/test_vfs.c \
- $(TOP)/src/test_windirent.c \
- $(TOP)/src/test_window.c \
- $(TOP)/src/test_wsd.c \
- $(TOP)/ext/fts3/fts3_term.c \
- $(TOP)/ext/fts3/fts3_test.c \
- $(TOP)/ext/session/test_session.c \
- $(TOP)/ext/recover/sqlite3recover.c \
- $(TOP)/ext/recover/dbdata.c \
- $(TOP)/ext/recover/test_recover.c \
- $(TOP)/ext/rbu/test_rbu.c
-
-# Statically linked extensions
-#
-TESTSRC += \
- $(TOP)/ext/expert/sqlite3expert.c \
- $(TOP)/ext/expert/test_expert.c \
- $(TOP)/ext/misc/amatch.c \
- $(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/basexx.c \
- $(TOP)/ext/misc/carray.c \
- $(TOP)/ext/misc/cksumvfs.c \
- $(TOP)/ext/misc/closure.c \
- $(TOP)/ext/misc/csv.c \
- $(TOP)/ext/misc/decimal.c \
- $(TOP)/ext/misc/eval.c \
- $(TOP)/ext/misc/explain.c \
- $(TOP)/ext/misc/fileio.c \
- $(TOP)/ext/misc/fuzzer.c \
- $(TOP)/ext/fts5/fts5_tcl.c \
- $(TOP)/ext/fts5/fts5_test_mi.c \
- $(TOP)/ext/fts5/fts5_test_tok.c \
- $(TOP)/ext/misc/ieee754.c \
- $(TOP)/ext/misc/mmapwarm.c \
- $(TOP)/ext/misc/nextchar.c \
- $(TOP)/ext/misc/normalize.c \
- $(TOP)/ext/misc/percentile.c \
- $(TOP)/ext/misc/prefixes.c \
- $(TOP)/ext/misc/qpvtab.c \
- $(TOP)/ext/misc/regexp.c \
- $(TOP)/ext/misc/remember.c \
- $(TOP)/ext/misc/series.c \
- $(TOP)/ext/misc/spellfix.c \
- $(TOP)/ext/misc/totype.c \
- $(TOP)/ext/misc/unionvtab.c \
- $(TOP)/ext/misc/wholenumber.c \
- $(TOP)/ext/misc/zipfile.c \
- $(TOP)/ext/userauth/userauth.c \
- $(TOP)/ext/rtree/test_rtreedoc.c
-
-# Source code to the library files needed by the test fixture
-#
-TESTSRC2 = \
- $(TOP)/src/attach.c \
- $(TOP)/src/backup.c \
- $(TOP)/src/bitvec.c \
- $(TOP)/src/btree.c \
- $(TOP)/src/build.c \
- $(TOP)/src/ctime.c \
- $(TOP)/src/date.c \
- $(TOP)/src/dbpage.c \
- $(TOP)/src/dbstat.c \
- $(TOP)/src/expr.c \
- $(TOP)/src/func.c \
- $(TOP)/src/global.c \
- $(TOP)/src/insert.c \
- $(TOP)/src/wal.c \
- $(TOP)/src/main.c \
- $(TOP)/src/mem5.c \
- $(TOP)/src/os.c \
- $(TOP)/src/os_kv.c \
- $(TOP)/src/os_unix.c \
- $(TOP)/src/os_win.c \
- $(TOP)/src/pager.c \
- $(TOP)/src/pragma.c \
- $(TOP)/src/prepare.c \
- $(TOP)/src/printf.c \
- $(TOP)/src/random.c \
- $(TOP)/src/pcache.c \
- $(TOP)/src/pcache1.c \
- $(TOP)/src/select.c \
- $(TOP)/src/tokenize.c \
- $(TOP)/src/treeview.c \
- $(TOP)/src/utf.c \
- $(TOP)/src/util.c \
- $(TOP)/src/vdbeapi.c \
- $(TOP)/src/vdbeaux.c \
- $(TOP)/src/vdbe.c \
- $(TOP)/src/vdbemem.c \
- $(TOP)/src/vdbetrace.c \
- $(TOP)/src/vdbevtab.c \
- $(TOP)/src/where.c \
- $(TOP)/src/wherecode.c \
- $(TOP)/src/whereexpr.c \
- $(TOP)/src/window.c \
- parse.c \
- $(TOP)/ext/fts3/fts3.c \
- $(TOP)/ext/fts3/fts3_aux.c \
- $(TOP)/ext/fts3/fts3_expr.c \
- $(TOP)/ext/fts3/fts3_term.c \
- $(TOP)/ext/fts3/fts3_tokenizer.c \
- $(TOP)/ext/fts3/fts3_write.c \
- $(TOP)/ext/async/sqlite3async.c \
- $(TOP)/ext/session/sqlite3session.c \
- $(TOP)/ext/misc/stmt.c \
- fts5.c
-
-# Header files used by all library source files.
-#
-HDR = \
- $(TOP)/src/btree.h \
- $(TOP)/src/btreeInt.h \
- $(TOP)/src/hash.h \
- $(TOP)/src/hwtime.h \
- keywordhash.h \
- $(TOP)/src/msvc.h \
- $(TOP)/src/mutex.h \
- opcodes.h \
- $(TOP)/src/os.h \
- $(TOP)/src/os_common.h \
- $(TOP)/src/os_setup.h \
- $(TOP)/src/os_win.h \
- $(TOP)/src/pager.h \
- $(TOP)/src/pcache.h \
- parse.h \
- $(TOP)/src/pragma.h \
- sqlite3.h \
- $(TOP)/src/sqlite3ext.h \
- $(TOP)/src/sqliteInt.h \
- $(TOP)/src/sqliteLimit.h \
- $(TOP)/src/vdbe.h \
- $(TOP)/src/vdbeInt.h \
- $(TOP)/src/vxworks.h \
- $(TOP)/src/whereInt.h \
- sqlite_cfg.h
-
-# Header files used by extensions
-#
-EXTHDR += \
- $(TOP)/ext/fts3/fts3.h \
- $(TOP)/ext/fts3/fts3Int.h \
- $(TOP)/ext/fts3/fts3_hash.h \
- $(TOP)/ext/fts3/fts3_tokenizer.h
-EXTHDR += \
- $(TOP)/ext/rtree/rtree.h \
- $(TOP)/ext/rtree/geopoly.c
-EXTHDR += \
- $(TOP)/ext/icu/sqliteicu.h
-EXTHDR += \
- $(TOP)/ext/rtree/sqlite3rtree.h
-EXTHDR += \
- $(TOP)/ext/userauth/sqlite3userauth.h
-
-# executables needed for testing
-#
-TESTPROGS = \
- testfixture$(TEXE) \
- sqlite3$(TEXE) \
- sqlite3_analyzer$(TEXE) \
- sqldiff$(TEXE) \
- dbhash$(TEXE) \
- sqltclsh$(TEXE)
-
-# Databases containing fuzzer test cases
-#
-FUZZDATA = \
- $(TOP)/test/fuzzdata1.db \
- $(TOP)/test/fuzzdata2.db \
- $(TOP)/test/fuzzdata3.db \
- $(TOP)/test/fuzzdata4.db \
- $(TOP)/test/fuzzdata5.db \
- $(TOP)/test/fuzzdata6.db \
- $(TOP)/test/fuzzdata7.db \
- $(TOP)/test/fuzzdata8.db
-
-# Standard options to testfixture
+# main.mk will fill out T.cc.sqlite with additional flags common to
+# all builds.
#
-TESTOPTS = --verbose=file --output=test-out.txt
+T.cc.sqlite += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite
-# Extra compiler options for various shell tools
-#
-SHELL_OPT += -DSQLITE_DQS=0
-SHELL_OPT += -DSQLITE_ENABLE_FTS4
-#SHELL_OPT += -DSQLITE_ENABLE_FTS5
-SHELL_OPT += -DSQLITE_ENABLE_RTREE
-SHELL_OPT += -DSQLITE_ENABLE_EXPLAIN_COMMENTS
-SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
-SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
-SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
-SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
-SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
-SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
-FUZZERSHELL_OPT =
-FUZZCHECK_OPT += -I$(TOP)/test
-FUZZCHECK_OPT += -I$(TOP)/ext/recover
-FUZZCHECK_OPT += \
- -DSQLITE_OSS_FUZZ \
- -DSQLITE_ENABLE_BYTECODE_VTAB \
- -DSQLITE_ENABLE_DBPAGE_VTAB \
- -DSQLITE_ENABLE_DBSTAT_VTAB \
- -DSQLITE_ENABLE_BYTECODE_VTAB \
- -DSQLITE_ENABLE_DESERIALIZE \
- -DSQLITE_ENABLE_EXPLAIN_COMMENTS \
- -DSQLITE_ENABLE_FTS3_PARENTHESIS \
- -DSQLITE_ENABLE_FTS4 \
- -DSQLITE_ENABLE_FTS5 \
- -DSQLITE_ENABLE_GEOPOLY \
- -DSQLITE_ENABLE_MATH_FUNCTIONS \
- -DSQLITE_ENABLE_MEMSYS5 \
- -DSQLITE_ENABLE_NORMALIZE \
- -DSQLITE_ENABLE_OFFSET_SQL_FUNC \
- -DSQLITE_ENABLE_PREUPDATE_HOOK \
- -DSQLITE_ENABLE_RTREE \
- -DSQLITE_ENABLE_SESSION \
- -DSQLITE_ENABLE_STMTVTAB \
- -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION \
- -DSQLITE_ENABLE_STAT4 \
- -DSQLITE_ENABLE_STMT_SCANSTATUS \
- -DSQLITE_MAX_MEMORY=50000000 \
- -DSQLITE_MAX_MMAP_SIZE=0 \
- -DSQLITE_OMIT_LOAD_EXTENSION \
- -DSQLITE_PRINTF_PRECISION_LIMIT=1000 \
- -DSQLITE_PRIVATE=""
-
-FUZZCHECK_SRC += $(TOP)/test/fuzzcheck.c
-FUZZCHECK_SRC += $(TOP)/test/ossfuzz.c
-FUZZCHECK_SRC += $(TOP)/test/fuzzinvariants.c
-FUZZCHECK_SRC += $(TOP)/ext/recover/dbdata.c
-FUZZCHECK_SRC += $(TOP)/ext/recover/sqlite3recover.c
-FUZZCHECK_SRC += $(TOP)/test/vt02.c
-DBFUZZ_OPT =
-ST_OPT = -DSQLITE_OS_KV_OPTIONAL
-
-
-# In wasi-sdk builds, disable the CLI shell build in the "all" target.
-SQLITE3_SHELL_TARGET_ = sqlcipher$(TEXE)
-SQLITE3_SHELL_TARGET_1 =
-SQLITE3_SHELL_TARGET = $(SQLITE3_SHELL_TARGET_@HAVE_WASI_SDK@)
-
-# This is the default Makefile target. The objects listed here
-# are what get build when you type just "make" with no arguments.
#
-all: sqlite3.h libsqlcipher.la $(SQLITE3_SHELL_TARGET) \
- $(HAVE_TCL:1=libtclsqlite3.la)
-
-Makefile: $(TOP)/Makefile.in
- ./config.status
-
-sqlcipher.pc: $(TOP)/sqlcipher.pc.in
- ./config.status
-
-libsqlcipher.la: $(LIBOBJ)
- $(LTLINK) -no-undefined -o $@ $(LIBOBJ) $(TLIBS) \
- ${ALLOWRELEASE} -rpath "$(libdir)" -version-info "8:6:8"
-
-libtclsqlite3.la: tclsqlite.lo libsqlcipher.la
- $(LTLINK) -no-undefined -o $@ tclsqlite.lo \
- libsqlcipher.la @TCL_STUB_LIB_SPEC@ $(TLIBS) \
- -rpath "$(TCLLIBDIR)" \
- -version-info "8:6:8" \
- -avoid-version
-
-sqlcipher$(TEXE): shell.c sqlite3.c
- $(LTLINK) $(READLINE_FLAGS) $(SHELL_OPT) -o $@ \
- shell.c sqlite3.c \
- $(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
-
-sqldiff$(TEXE): $(TOP)/tool/sqldiff.c sqlite3.lo sqlite3.h
- $(LTLINK) -o $@ $(TOP)/tool/sqldiff.c sqlite3.lo $(TLIBS)
-
-dbhash$(TEXE): $(TOP)/tool/dbhash.c sqlite3.lo sqlite3.h
- $(LTLINK) -o $@ $(TOP)/tool/dbhash.c sqlite3.lo $(TLIBS)
-
-scrub$(TEXE): $(TOP)/ext/misc/scrub.c sqlite3.lo
- $(LTLINK) -o $@ -I. -DSCRUB_STANDALONE \
- $(TOP)/ext/misc/scrub.c sqlite3.lo $(TLIBS)
-
-srcck1$(BEXE): $(TOP)/tool/srcck1.c
- $(BCC) -o srcck1$(BEXE) $(TOP)/tool/srcck1.c
-
-sourcetest: srcck1$(BEXE) sqlite3.c
- ./srcck1 sqlite3.c
-
-src-verify: $(TOP)/tool/src-verify.c
- $(BCC) -o src-verify$(BEXE) $(TOP)/tool/src-verify.c
-
-verify-source: ./src-verify
- ./src-verify $(TOP)
-
-fuzzershell$(TEXE): $(TOP)/tool/fuzzershell.c sqlite3.c sqlite3.h
- $(LTLINK) -o $@ $(FUZZERSHELL_OPT) \
- $(TOP)/tool/fuzzershell.c sqlite3.c $(TLIBS)
-
-fuzzcheck$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
- $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
-
-fuzzcheck-asan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
- $(LTLINK) -o $@ -fsanitize=address $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
-
-fuzzcheck-ubsan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
- $(LTLINK) -o $@ -fsanitize=undefined $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
-
-ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
- $(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
- $(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
-
-sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h
- $(LTLINK) -o $@ $(TOP)/test/sessionfuzz.c $(TLIBS)
-
-dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h
- $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS)
-
-DBFUZZ2_OPTS = \
- -DSQLITE_THREADSAFE=0 \
- -DSQLITE_OMIT_LOAD_EXTENSION \
- -DSQLITE_DEBUG \
- -DSQLITE_ENABLE_DBSTAT_VTAB \
- -DSQLITE_ENABLE_BYTECODE_VTAB \
- -DSQLITE_ENABLE_RTREE \
- -DSQLITE_ENABLE_FTS4 \
- -DSQLITE_ENABLE_FTS5
-
-dbfuzz2$(TEXE): $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
- $(CC) $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
- -DSTANDALONE -o dbfuzz2 \
- $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
- mkdir -p dbfuzz2-dir
- cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
-
-dbfuzz2-asan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
- clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
- -fsanitize=fuzzer,undefined,address -o dbfuzz2-asan \
- $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
- mkdir -p dbfuzz2-dir
- cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
-
-dbfuzz2-msan: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h
- clang-6.0 $(OPT_FEATURE_FLAGS) $(OPTS) -I. -g -O0 \
- -fsanitize=fuzzer,undefined,memory -o dbfuzz2-msan \
- $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c $(TLIBS)
- mkdir -p dbfuzz2-dir
- cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir
-
-mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c
- $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \
- $(TLIBS) -rpath "$(libdir)"
-
-MPTEST1=./mptester$(TEXE) mptest.db $(TOP)/mptest/crash01.test --repeat 20
-MPTEST2=./mptester$(TEXE) mptest.db $(TOP)/mptest/multiwrite01.test --repeat 20
-mptest: mptester$(TEXE)
- rm -f mptest.db
- $(MPTEST1) --journalmode DELETE
- $(MPTEST2) --journalmode WAL
- $(MPTEST1) --journalmode WAL
- $(MPTEST2) --journalmode PERSIST
- $(MPTEST1) --journalmode PERSIST
- $(MPTEST2) --journalmode TRUNCATE
- $(MPTEST1) --journalmode TRUNCATE
- $(MPTEST2) --journalmode DELETE
-
-
-has_tclsh84:
- sh $(TOP)/tool/cktclsh.sh 8.4 $(TCLSH_CMD)
- touch has_tclsh84
-
-has_tclsh85:
- sh $(TOP)/tool/cktclsh.sh 8.5 $(TCLSH_CMD)
- touch has_tclsh85
-
-
-# This target creates a directory named "tsrc" and fills it with
-# copies of all of the C source code and header files needed to
-# build on the target system. Some of the C source code and header
-# files are automatically generated. This target takes care of
-# all that automatic generation.
-#
-.target_source: $(SRC) $(TOP)/tool/vdbe-compress.tcl has_tclsh84 fts5.c
- rm -rf tsrc
- mkdir tsrc
- cp -f $(SRC) tsrc
- rm tsrc/sqlite.h.in tsrc/parse.y
- $(TCLSH_CMD) $(TOP)/tool/vdbe-compress.tcl $(OPTS) vdbe.new
- mv vdbe.new tsrc/vdbe.c
- cp fts5.c fts5.h tsrc
- touch .target_source
-
-sqlite3.c: .target_source $(TOP)/tool/mksqlite3c.tcl src-verify has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl $(AMALGAMATION_LINE_MACROS)
- cp tsrc/sqlite3ext.h .
- cp $(TOP)/ext/session/sqlite3session.h .
-
-sqlite3r.h: sqlite3.h has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) --enable-recover >sqlite3r.h
-
-sqlite3r.c: sqlite3.c sqlite3r.h has_tclsh84
- cp $(TOP)/ext/recover/sqlite3recover.c tsrc/
- cp $(TOP)/ext/recover/sqlite3recover.h tsrc/
- cp $(TOP)/ext/recover/dbdata.c tsrc/
- $(TCLSH_CMD) $(TOP)/tool/mksqlite3c.tcl --enable-recover $(AMALGAMATION_LINE_MACROS)
-
-sqlite3ext.h: .target_source
- cp tsrc/sqlite3ext.h .
-
-tclsqlite3.c: sqlite3.c
- echo '#ifndef USE_SYSTEM_SQLITE' >tclsqlite3.c
- cat sqlite3.c >>tclsqlite3.c
- echo '#endif /* USE_SYSTEM_SQLITE */' >>tclsqlite3.c
- cat $(TOP)/src/tclsqlite.c >>tclsqlite3.c
-
-sqlite3-all.c: sqlite3.c $(TOP)/tool/split-sqlite3c.tcl has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/split-sqlite3c.tcl
-
-# Rule to build the amalgamation
+# $(JIMSH) and $(CFLAGS.jimsh) are documented in main.mk. $(JIMSH)
+# must start with a path component so that it can be invoked as a
+# shell command.
#
-sqlite3.lo: sqlite3.c
- $(LTCOMPILE) $(TEMP_STORE) -c sqlite3.c
+CFLAGS.jimsh = @CFLAGS_JIMSH@
+JIMSH = ./jimsh$(T.exe)
-# Rules to build the LEMON compiler generator
#
-lemon$(BEXE): $(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
- $(BCC) -o $@ $(TOP)/tool/lemon.c
- cp $(TOP)/tool/lempar.c .
-
-# Rules to build the program that generates the source-id
+# $(B.tclsh) is documented in main.mk.
#
-mksourceid$(BEXE): $(TOP)/tool/mksourceid.c
- $(BCC) -o $@ $(TOP)/tool/mksourceid.c
+B.tclsh = @BTCLSH@
+$(B.tclsh):
-# Rules to build individual *.o files from generated *.c files. This
-# applies to:
#
-# parse.o
-# opcodes.o
+# $(OPT_FEATURE_FLAGS) is documented in main.mk.
#
-parse.lo: parse.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c parse.c
-
-opcodes.lo: opcodes.c
- $(LTCOMPILE) $(TEMP_STORE) -c opcodes.c
-
-# BEGIN CRYPTO
-crypto.lo: $(TOP)/src/crypto.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto.c
-crypto_impl.lo: $(TOP)/src/crypto_impl.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto_impl.c
-crypto_openssl.lo: $(TOP)/src/crypto_openssl.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto_openssl.c
-crypto_nss.lo: $(TOP)/src/crypto_nss.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto_nss.c
-crypto_libtomcrypt.lo: $(TOP)/src/crypto_libtomcrypt.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto_libtomcrypt.c
-crypto_cc.lo: $(TOP)/src/crypto_cc.c $(HDR)
- $(LTCOMPILE) -c $(TOP)/src/crypto_cc.c
-# END CRYPTO
-
-# Rules to build individual *.o files from files in the src directory.
+# The appending of $(OPTIONS) to $(OPT_FEATURE_FLAGS) is historical
+# and somewhat confusing because there's another var, $(OPTS), which
+# has a similar (but not identical) role.
#
-alter.lo: $(TOP)/src/alter.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/alter.c
-
-analyze.lo: $(TOP)/src/analyze.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/analyze.c
-
-attach.lo: $(TOP)/src/attach.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/attach.c
-
-auth.lo: $(TOP)/src/auth.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/auth.c
-
-backup.lo: $(TOP)/src/backup.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/backup.c
-
-bitvec.lo: $(TOP)/src/bitvec.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/bitvec.c
-
-btmutex.lo: $(TOP)/src/btmutex.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/btmutex.c
-
-btree.lo: $(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/btree.c
-
-build.lo: $(TOP)/src/build.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/build.c
-
-callback.lo: $(TOP)/src/callback.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/callback.c
-
-complete.lo: $(TOP)/src/complete.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/complete.c
-
-ctime.lo: $(TOP)/src/ctime.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/ctime.c
-
-date.lo: $(TOP)/src/date.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/date.c
-
-dbpage.lo: $(TOP)/src/dbpage.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbpage.c
-
-dbstat.lo: $(TOP)/src/dbstat.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/dbstat.c
-
-delete.lo: $(TOP)/src/delete.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/delete.c
-
-expr.lo: $(TOP)/src/expr.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/expr.c
-
-fault.lo: $(TOP)/src/fault.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/fault.c
-
-fkey.lo: $(TOP)/src/fkey.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/fkey.c
-
-func.lo: $(TOP)/src/func.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/func.c
-
-global.lo: $(TOP)/src/global.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/global.c
-
-hash.lo: $(TOP)/src/hash.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/hash.c
-
-insert.lo: $(TOP)/src/insert.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/insert.c
-
-json.lo: $(TOP)/src/json.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/json.c
-
-legacy.lo: $(TOP)/src/legacy.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/legacy.c
-
-loadext.lo: $(TOP)/src/loadext.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/loadext.c
-
-main.lo: $(TOP)/src/main.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c
-
-malloc.lo: $(TOP)/src/malloc.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/malloc.c
-
-mem0.lo: $(TOP)/src/mem0.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem0.c
-
-mem1.lo: $(TOP)/src/mem1.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem1.c
-
-mem2.lo: $(TOP)/src/mem2.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem2.c
-
-mem3.lo: $(TOP)/src/mem3.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem3.c
-
-mem5.lo: $(TOP)/src/mem5.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mem5.c
-
-memdb.lo: $(TOP)/src/memdb.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/memdb.c
-
-memjournal.lo: $(TOP)/src/memjournal.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/memjournal.c
-
-mutex.lo: $(TOP)/src/mutex.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex.c
-
-mutex_noop.lo: $(TOP)/src/mutex_noop.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_noop.c
-
-mutex_unix.lo: $(TOP)/src/mutex_unix.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_unix.c
-
-mutex_w32.lo: $(TOP)/src/mutex_w32.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/mutex_w32.c
-
-notify.lo: $(TOP)/src/notify.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/notify.c
-
-pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pager.c
-
-pcache.lo: $(TOP)/src/pcache.c $(HDR) $(TOP)/src/pcache.h
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pcache.c
-
-pcache1.lo: $(TOP)/src/pcache1.c $(HDR) $(TOP)/src/pcache.h
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pcache1.c
-
-os.lo: $(TOP)/src/os.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os.c
-
-os_kv.lo: $(TOP)/src/os_kv.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_kv.c
-
-os_unix.lo: $(TOP)/src/os_unix.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_unix.c
-
-os_win.lo: $(TOP)/src/os_win.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/os_win.c
-
-pragma.lo: $(TOP)/src/pragma.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pragma.c
-
-prepare.lo: $(TOP)/src/prepare.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/prepare.c
-
-printf.lo: $(TOP)/src/printf.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/printf.c
-
-random.lo: $(TOP)/src/random.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/random.c
-
-resolve.lo: $(TOP)/src/resolve.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/resolve.c
+OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ $(OPTIONS)
-rowset.lo: $(TOP)/src/rowset.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/rowset.c
-
-select.lo: $(TOP)/src/select.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/select.c
-
-status.lo: $(TOP)/src/status.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/status.c
-
-table.lo: $(TOP)/src/table.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
-
-threads.lo: $(TOP)/src/threads.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c
-
-tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
-
-treeview.lo: $(TOP)/src/treeview.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/treeview.c
-
-trigger.lo: $(TOP)/src/trigger.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/trigger.c
-
-update.lo: $(TOP)/src/update.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/update.c
-
-upsert.lo: $(TOP)/src/upsert.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/upsert.c
-
-utf.lo: $(TOP)/src/utf.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/utf.c
-
-util.lo: $(TOP)/src/util.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/util.c
-
-vacuum.lo: $(TOP)/src/vacuum.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vacuum.c
-
-vdbe.lo: $(TOP)/src/vdbe.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbe.c
-
-vdbeapi.lo: $(TOP)/src/vdbeapi.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbeapi.c
-
-vdbeaux.lo: $(TOP)/src/vdbeaux.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbeaux.c
-
-vdbeblob.lo: $(TOP)/src/vdbeblob.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbeblob.c
-
-vdbemem.lo: $(TOP)/src/vdbemem.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbemem.c
-
-vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbesort.c
-
-vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c
-
-vdbevtab.lo: $(TOP)/src/vdbevtab.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbevtab.c
-
-vtab.lo: $(TOP)/src/vtab.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
-
-wal.lo: $(TOP)/src/wal.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c
-
-walker.lo: $(TOP)/src/walker.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c
-
-where.lo: $(TOP)/src/where.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/where.c
-
-wherecode.lo: $(TOP)/src/wherecode.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wherecode.c
-
-whereexpr.lo: $(TOP)/src/whereexpr.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/whereexpr.c
-
-window.lo: $(TOP)/src/window.c $(HDR)
- $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/window.c
-
-tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR)
- $(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c
-
-tclsqlite-shell.lo: $(TOP)/src/tclsqlite.c $(HDR)
- $(LTCOMPILE) -DTCLSH -o $@ -c $(TOP)/src/tclsqlite.c
-
-tclsqlite-stubs.lo: $(TOP)/src/tclsqlite.c $(HDR)
- $(LTCOMPILE) -DUSE_TCL_STUBS=1 -o $@ -c $(TOP)/src/tclsqlite.c
-
-tclsqlcipher$(TEXE): tclsqlite-shell.lo libsqlcipher.la
- $(LTLINK) -o $@ tclsqlite-shell.lo \
- libsqlcipher.la $(LIBTCL)
-
-# Rules to build opcodes.c and opcodes.h
#
-opcodes.c: opcodes.h $(TOP)/tool/mkopcodec.tcl has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/mkopcodec.tcl opcodes.h >opcodes.c
-
-opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl has_tclsh84
- cat parse.h $(TOP)/src/vdbe.c | $(TCLSH_CMD) $(TOP)/tool/mkopcodeh.tcl >opcodes.h
-
-# Rules to build parse.c and parse.h - the outputs of lemon.
+# Version (X.Y.Z) number for the SQLite being compiled.
#
-parse.h: parse.c
-
-parse.c: $(TOP)/src/parse.y lemon$(BEXE)
- cp $(TOP)/src/parse.y .
- ./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) -S parse.y
-
-sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
-
-sqlite3rc.h: $(TOP)/src/sqlite3.rc $(TOP)/VERSION has_tclsh84
- echo '#ifndef SQLITE_RESOURCE_VERSION' >$@
- echo -n '#define SQLITE_RESOURCE_VERSION ' >>$@
- cat $(TOP)/VERSION | $(TCLSH_CMD) $(TOP)/tool/replace.tcl exact . , >>$@
- echo '#endif' >>sqlite3rc.h
-
-keywordhash.h: $(TOP)/tool/mkkeywordhash.c
- $(BCC) -o mkkeywordhash$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) $(TOP)/tool/mkkeywordhash.c
- ./mkkeywordhash$(BEXE) >keywordhash.h
-
-# Source files that go into making shell.c
-SHELL_SRC = \
- $(TOP)/src/shell.c.in \
- $(TOP)/ext/misc/appendvfs.c \
- $(TOP)/ext/misc/completion.c \
- $(TOP)/ext/consio/console_io.c \
- $(TOP)/ext/consio/console_io.h \
- $(TOP)/ext/misc/decimal.c \
- $(TOP)/ext/misc/basexx.c \
- $(TOP)/ext/misc/base64.c \
- $(TOP)/ext/misc/base85.c \
- $(TOP)/ext/misc/fileio.c \
- $(TOP)/ext/misc/ieee754.c \
- $(TOP)/ext/misc/regexp.c \
- $(TOP)/ext/misc/series.c \
- $(TOP)/ext/misc/shathree.c \
- $(TOP)/ext/misc/sqlar.c \
- $(TOP)/ext/misc/uint.c \
- $(TOP)/ext/expert/sqlite3expert.c \
- $(TOP)/ext/expert/sqlite3expert.h \
- $(TOP)/ext/misc/zipfile.c \
- $(TOP)/ext/misc/memtrace.c \
- $(TOP)/ext/misc/pcachetrace.c \
- $(TOP)/ext/recover/dbdata.c \
- $(TOP)/ext/recover/sqlite3recover.c \
- $(TOP)/ext/recover/sqlite3recover.h \
- $(TOP)/src/test_windirent.c
+PACKAGE_VERSION = @PACKAGE_VERSION@
-shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl has_tclsh84
- $(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c
-
-
-
-
-# Rules to build the extension objects.
#
-icu.lo: $(TOP)/ext/icu/icu.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/icu/icu.c
-
-fts3.lo: $(TOP)/ext/fts3/fts3.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c
-
-fts3_aux.lo: $(TOP)/ext/fts3/fts3_aux.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_aux.c
-
-fts3_expr.lo: $(TOP)/ext/fts3/fts3_expr.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_expr.c
-
-fts3_hash.lo: $(TOP)/ext/fts3/fts3_hash.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_hash.c
-
-fts3_icu.lo: $(TOP)/ext/fts3/fts3_icu.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_icu.c
-
-fts3_porter.lo: $(TOP)/ext/fts3/fts3_porter.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter.c
-
-fts3_snippet.lo: $(TOP)/ext/fts3/fts3_snippet.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_snippet.c
-
-fts3_tokenizer.lo: $(TOP)/ext/fts3/fts3_tokenizer.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer.c
-
-fts3_tokenizer1.lo: $(TOP)/ext/fts3/fts3_tokenizer1.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenizer1.c
-
-fts3_tokenize_vtab.lo: $(TOP)/ext/fts3/fts3_tokenize_vtab.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_tokenize_vtab.c
-
-fts3_unicode.lo: $(TOP)/ext/fts3/fts3_unicode.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode.c
-
-fts3_unicode2.lo: $(TOP)/ext/fts3/fts3_unicode2.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_unicode2.c
-
-fts3_write.lo: $(TOP)/ext/fts3/fts3_write.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_write.c
-
-rtree.lo: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
-
-userauth.lo: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
-
-sqlite3session.lo: $(TOP)/ext/session/sqlite3session.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/session/sqlite3session.c
-
-stmt.lo: $(TOP)/ext/misc/stmt.c
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/misc/stmt.c
-
-# FTS5 things
-#
-FTS5_SRC = \
- $(TOP)/ext/fts5/fts5.h \
- $(TOP)/ext/fts5/fts5Int.h \
- $(TOP)/ext/fts5/fts5_aux.c \
- $(TOP)/ext/fts5/fts5_buffer.c \
- $(TOP)/ext/fts5/fts5_main.c \
- $(TOP)/ext/fts5/fts5_config.c \
- $(TOP)/ext/fts5/fts5_expr.c \
- $(TOP)/ext/fts5/fts5_hash.c \
- $(TOP)/ext/fts5/fts5_index.c \
- fts5parse.c fts5parse.h \
- $(TOP)/ext/fts5/fts5_storage.c \
- $(TOP)/ext/fts5/fts5_tokenize.c \
- $(TOP)/ext/fts5/fts5_unicode2.c \
- $(TOP)/ext/fts5/fts5_varint.c \
- $(TOP)/ext/fts5/fts5_vocab.c \
-
-fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
- cp $(TOP)/ext/fts5/fts5parse.y .
- rm -f fts5parse.h
- ./lemon$(BEXE) $(OPTS) -S fts5parse.y
-
-fts5parse.h: fts5parse.c
-
-fts5.c: $(FTS5_SRC) has_tclsh84
- $(TCLSH_CMD) $(TOP)/ext/fts5/tool/mkfts5c.tcl
- cp $(TOP)/ext/fts5/fts5.h .
-
-fts5.lo: fts5.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c fts5.c
-
-sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR)
- $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rbu/sqlite3rbu.c
-
-
-# Rules to build the 'testfixture' application.
-#
-# If using the amalgamation, use sqlite3.c directly to build the test
-# fixture. Otherwise link against libsqlcipher.la. (This distinction is
-# necessary because the test fixture requires non-API symbols which are
-# hidden when the library is built via the amalgamation).
-#
-TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1
-TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
-TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE
-TESTFIXTURE_FLAGS += -DBUILD_sqlite
-TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
-TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
-TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
-TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
-TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
-TESTFIXTURE_FLAGS += -DSQLITE_CKSUMVFS_STATIC
-
-TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlcipher.la
-TESTFIXTURE_SRC1 = sqlite3.c
-TESTFIXTURE_SRC = $(TESTSRC) $(TOP)/src/tclsqlite.c
-TESTFIXTURE_SRC += $(TESTFIXTURE_SRC$(USE_AMALGAMATION))
-
-testfixture$(TEXE): has_tclsh85 $(TESTFIXTURE_SRC)
- $(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \
- -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS)
-
-coretestprogs: $(TESTPROGS)
-
-testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE)
-
-# A very detailed test running most or all test cases
-fulltest: alltest fuzztest
-
-# Run most or all tcl test cases
-alltest: $(TESTPROGS)
- ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS)
-
-# Really really long testing
-soaktest: $(TESTPROGS)
- ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS)
-
-# Do extra testing but not everything.
-fulltestonly: $(TESTPROGS) fuzztest
- ./testfixture$(TEXE) $(TOP)/test/full.test
+# Filename extensions for binaries and libraries
+#
+B.exe = @BUILD_EXEEXT@
+T.exe = @TARGET_EXEEXT@
+B.dll = @BUILD_DLLEXT@
+T.dll = @TARGET_DLLEXT@
+B.lib = @BUILD_LIBEXT@
+T.lib = @TARGET_LIBEXT@
-# Fuzz testing
#
-# WARNING: When the "fuzztest" target is run by the testrunner.tcl script,
-# it does not actually run this code. Instead, it schedules equivalent
-# commands. Therefore, if this target is updated, then code in
-# testrunner_data.tcl (search for "trd_fuzztest_data") must also be updated.
+# $(HAVE_TCL) is 1 if the configure script was able to locate the
+# tclConfig.sh file, else it is 0. When this variable is 1, the TCL
+# extension library (libtclsqlite3.so) and related testing apps are
+# built.
#
-fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) sessionfuzz$(TEXE)
- ./fuzzcheck$(TEXE) $(FUZZDATA)
- ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
-
-valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) sessionfuzz$(TEXE)
- valgrind ./fuzzcheck$(TEXE) --cell-size-check --limit-mem 10M $(FUZZDATA)
- valgrind ./sessionfuzz$(TEXE) run $(TOP)/test/sessionfuzz-data1.db
+HAVE_TCL = @HAVE_TCL@
-# The veryquick.test TCL tests.
#
-tcltest: ./testfixture$(TEXE)
- ./testfixture$(TEXE) $(TOP)/test/veryquick.test $(TESTOPTS)
-
-# Runs all the same tests cases as the "tcltest" target but uses
-# the testrunner.tcl script to run them in multiple cores
-# concurrently.
-testrunner: testfixture$(TEXE)
- ./testfixture$(TEXE) $(TOP)/test/testrunner.tcl
-
-# Runs both fuzztest and testrunner, consecutively.
+# $(TCLSH_CMD) is the command to use for tclsh - normally just
+# "tclsh", but we may know the specific version we want to use. This
+# must point to a canonical TCL interpreter, not JimTCL.
#
-devtest: srctree-check testfixture$(TEXE) fuzztest testrunner
-
-mdevtest: srctree-check has_tclsh85
- $(TCLSH_CMD) $(TOP)/test/testrunner.tcl mdevtest
-
-sdevtest: has_tclsh85
- $(TCLSH_CMD) $(TOP)/test/testrunner.tcl sdevtest
+TCLSH_CMD = @TCLSH_CMD@
+TCL_CONFIG_SH = @TCL_CONFIG_SH@
-# Validate that various generated files in the source tree
-# are up-to-date.
#
-srctree-check: $(TOP)/tool/srctree-check.tcl
- $(TCLSH_CMD) $(TOP)/tool/srctree-check.tcl
-
-# Testing for a release
+# TCL config info from tclConfig.sh
#
-releasetest: srctree-check testfixture$(TEXE)
- ./testfixture$(TEXE) $(TOP)/test/testrunner.tcl release
-
-# Minimal testing that runs in less than 3 minutes
+# We have to inject this differently in main.mk to accommodate static
+# makefiles, so we don't currently bother to export it here. This
+# block is retained in case we decide that we do indeed need to export
+# it at configure-time instead of calculate it at make-time.
#
-quicktest: ./testfixture$(TEXE)
- ./testfixture$(TEXE) $(TOP)/test/extraquick.test $(TESTOPTS)
-
-# This is the common case. Run many tests that do not take too long,
-# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
+#TCL_INCLUDE_SPEC = @TCL_INCLUDE_SPEC@
+#TCL_LIB_SPEC = @TCL_LIB_SPEC@
+#TCL_STUB_LIB_SPEC = @TCL_STUB_LIB_SPEC@
+#TCL_EXEC_PREFIX = @TCL_EXEC_PREFIX@
+#TCL_VERSION = @TCL_VERSION@
#
-test: srctree-check fuzztest sourcetest $(TESTPROGS) tcltest
-
-# Run a test using valgrind. This can take a really long time
-# because valgrind is so much slower than a native machine.
+# $(TCLLIBDIR) = where to install the tcl plugin. If this is empty, it
+# is calculated at make-time by the targets which need it but we
+# export it here so that it can be set at configure-time, so that
+# clients are not required to pass it at make-time, or may set it in
+# their environment to override it.
#
-valgrindtest: $(TESTPROGS) valgrindfuzz
- OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind $(TESTOPTS)
+TCLLIBDIR = @TCLLIBDIR@
-# A very fast test that checks basic sanity. The name comes from
-# the 60s-era electronics testing: "Turn it on and see if smoke
-# comes out."
#
-smoketest: $(TESTPROGS) fuzzcheck$(TEXE)
- ./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS)
-
-shelltest: $(TESTPROGS)
- ./testfixture$(TEXT) $(TOP)/test/permutations.test shell
-
-sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in has_tclsh85
- $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c
-
-sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
- $(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
-
-sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in has_tclsh85
- $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c
-
-sqltclsh$(TEXE): sqltclsh.c
- $(LTLINK) sqltclsh.c -o $@ $(LIBTCL) $(TLIBS)
-
-sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
- $(LTLINK) $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(TLIBS)
-
-CHECKER_DEPS =\
- $(TOP)/tool/mkccode.tcl \
- sqlite3.c \
- $(TOP)/src/tclsqlite.c \
- $(TOP)/ext/repair/sqlite3_checker.tcl \
- $(TOP)/ext/repair/checkindex.c \
- $(TOP)/ext/repair/checkfreelist.c \
- $(TOP)/ext/misc/btreeinfo.c \
- $(TOP)/ext/repair/sqlite3_checker.c.in
-
-sqlite3_checker.c: $(CHECKER_DEPS) has_tclsh85
- $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/ext/repair/sqlite3_checker.c.in >$@
-
-sqlite3_checker$(TEXE): sqlite3_checker.c
- $(LTLINK) sqlite3_checker.c -o $@ $(LIBTCL) $(TLIBS)
-
-dbdump$(TEXE): $(TOP)/ext/misc/dbdump.c sqlite3.lo
- $(LTLINK) -DDBDUMP_STANDALONE -o $@ \
- $(TOP)/ext/misc/dbdump.c sqlite3.lo $(TLIBS)
-
-dbtotxt$(TEXE): $(TOP)/tool/dbtotxt.c
- $(LTLINK)-o $@ $(TOP)/tool/dbtotxt.c
-
-showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/tool/showdb.c sqlite3.lo $(TLIBS)
-
-showstat4$(TEXE): $(TOP)/tool/showstat4.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/tool/showstat4.c sqlite3.lo $(TLIBS)
-
-showjournal$(TEXE): $(TOP)/tool/showjournal.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/tool/showjournal.c sqlite3.lo $(TLIBS)
-
-showwal$(TEXE): $(TOP)/tool/showwal.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/tool/showwal.c sqlite3.lo $(TLIBS)
-
-showshm$(TEXE): $(TOP)/tool/showshm.c
- $(LTLINK) -o $@ $(TOP)/tool/showshm.c
-
-index_usage$(TEXE): $(TOP)/tool/index_usage.c sqlite3.lo
- $(LTLINK) $(SHELL_OPT) -o $@ $(TOP)/tool/index_usage.c sqlite3.lo $(TLIBS)
-
-changeset$(TEXE): $(TOP)/ext/session/changeset.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/ext/session/changeset.c sqlite3.lo $(TLIBS)
-
-changesetfuzz$(TEXE): $(TOP)/ext/session/changesetfuzz.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/ext/session/changesetfuzz.c sqlite3.lo $(TLIBS)
-
-rollback-test$(TEXE): $(TOP)/tool/rollback-test.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/tool/rollback-test.c sqlite3.lo $(TLIBS)
-
-atrc$(TEXX): $(TOP)/test/atrc.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/test/atrc.c sqlite3.lo $(TLIBS)
-
-LogEst$(TEXE): $(TOP)/tool/logest.c sqlite3.h
- $(LTLINK) -I. -o $@ $(TOP)/tool/logest.c
-
-wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
- $(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.lo $(TLIBS)
-
-speedtest1$(TEXE): $(TOP)/test/speedtest1.c sqlite3.c Makefile
- $(LTLINK) $(ST_OPT) -o $@ $(TOP)/test/speedtest1.c sqlite3.c $(TLIBS)
-
-startup$(TEXE): $(TOP)/test/startup.c sqlite3.c
- $(CC) -Os -g -DSQLITE_THREADSAFE=0 -o $@ $(TOP)/test/startup.c sqlite3.c $(TLIBS)
-
-KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ
-
-kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c
- $(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS)
-
-rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo
- $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS)
-
-loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
- $(LTLINK) $(TOP)/tool/loadfts.c libsqlite3.la -o $@ $(TLIBS)
-
-# This target will fail if the SQLite amalgamation contains any exported
-# symbols that do not begin with "sqlite3_". It is run as part of the
-# releasetest.tcl script.
-#
-VALIDIDS=' sqlite3(changeset|changegroup|session)?_'
-checksymbols: sqlite3.o
- nm -g --defined-only sqlite3.o
- nm -g --defined-only sqlite3.o | egrep -v $(VALIDIDS); test $$? -ne 0
- echo '0 errors out of 1 tests'
-
-# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
-# a tarball named for the version number. Ex: sqlite-autoconf-3110000.tar.gz.
-# The snapshot-tarball target builds a tarball named by the SHA1 hash
+# Additional options when running tests using testrunner.tcl
+# This is usually either blank or --status.
#
-amalgamation-tarball: sqlite3.c sqlite3rc.h
- TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --normal
+TSTRNNR_OPTS = @TSTRNNR_OPTS@
-snapshot-tarball: sqlite3.c sqlite3rc.h
- TOP=$(TOP) sh $(TOP)/tool/mkautoconfamal.sh --snapshot
-
-# Build a ZIP archive containing various command-line tools.
#
-tool-zip: testfixture sqlite3 sqldiff sqlite3_analyzer $(TOP)/tool/mktoolzip.tcl
- ./testfixture $(TOP)/tool/mktoolzip.tcl
-
-# The next two rules are used to support the "threadtest" target. Building
-# threadtest runs a few thread-safety tests that are implemented in C. This
-# target is invoked by the releasetest.tcl script.
-#
-THREADTEST3_SRC = $(TOP)/test/threadtest3.c \
- $(TOP)/test/tt3_checkpoint.c \
- $(TOP)/test/tt3_index.c \
- $(TOP)/test/tt3_vacuum.c \
- $(TOP)/test/tt3_stress.c \
- $(TOP)/test/tt3_lookaside1.c
-
-threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC)
- $(LTLINK) $(TOP)/test/threadtest3.c $(TOP)/src/test_multiplex.c sqlite3.lo -o $@ $(TLIBS)
-
-threadtest: threadtest3$(TEXE)
- ./threadtest3$(TEXE)
-
-threadtest5: sqlite3.c $(TOP)/test/threadtest5.c
- $(LTLINK) $(TOP)/test/threadtest5.c sqlite3.c -o $@ $(TLIBS)
-
-# Standard install and cleanup targets
+# If gcov support was enabled by the configure script, add the appropriate
+# flags here. It's not always as easy as just having the user add the right
+# CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which
+# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs.
+# Supposedly GCC does the right thing if you use --coverage, but in
+# practice it still fails. See:
#
-lib_install: libsqlcipher.la
- $(INSTALL) -d $(DESTDIR)$(libdir)
- $(LTINSTALL) libsqlcipher.la $(DESTDIR)$(libdir)
-
-install: sqlcipher$(TEXE) lib_install sqlite3.h sqlcipher.pc ${HAVE_TCL:1=tcl_install}
- $(INSTALL) -d $(DESTDIR)$(bindir)
- $(LTINSTALL) sqlcipher$(TEXE) $(DESTDIR)$(bindir)
- $(INSTALL) -d $(DESTDIR)$(includedir)
- $(INSTALL) -m 0644 sqlite3.h $(DESTDIR)$(includedir)
- $(INSTALL) -m 0644 $(TOP)/src/sqlite3ext.h $(DESTDIR)$(includedir)
- $(INSTALL) -d $(DESTDIR)$(pkgconfigdir)
- $(INSTALL) -m 0644 sqlcipher.pc $(DESTDIR)$(pkgconfigdir)
-
-pkgIndex.tcl:
- echo 'package ifneeded sqlite3 $(RELEASE) [list load [file join $$dir libtclsqlite3[info sharedlibextension]] sqlite3]' > $@
-tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl
- $(INSTALL) -d $(DESTDIR)$(TCLLIBDIR)
- $(LTINSTALL) libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)
- rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a
- $(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR)
+# http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html
+#
+# for more info.
+#
+CFLAGS.gcov1 = -DSQLITE_COVERAGE_TEST=1 -fprofile-arcs -ftest-coverage
+LDFLAGS.gcov1 = -lgcov
+USE_GCOV = @USE_GCOV@
+T.compile.extras = $(CFLAGS.gcov$(USE_GCOV))
+T.link.extras = $(LDFLAGS.gcov$(USE_GCOV))
-clean:
- rm -f *.lo *.la *.o sqlcipher$(TEXE) libsqlcipher.la
- rm -f sqlite3.h opcodes.*
- rm -rf .libs .deps
- rm -f lemon$(BEXE) lempar.c parse.* sqlite*.tar.gz
- rm -f mkkeywordhash$(BEXE) keywordhash.h
- rm -f mksourceid$(BEXE)
- rm -f *.da *.bb *.bbg gmon.out
- rm -rf tsrc .target_source
- rm -f tclsqlcipher$(TEXE)
- rm -f testfixture$(TEXE) test.db
- rm -f LogEst$(TEXE) fts3view$(TEXE) rollback-test$(TEXE) showdb$(TEXE)
- rm -f showjournal$(TEXE) showstat4$(TEXE) showwal$(TEXE) speedtest1$(TEXE)
- rm -f wordcount$(TEXE) changeset$(TEXE)
- rm -f version-info$(TEXT)
- rm -f sqlite3.dll sqlite3.lib sqlite3.exp sqlite3.def
- rm -f sqlite3.c
- rm -f sqlite3rc.h
- rm -f shell.c sqlite3ext.h
- rm -f sqlite3_analyzer$(TEXE) sqlite3_analyzer.c
- rm -f sqlite-*-output.vsix
- rm -f mptester mptester.exe
- rm -f rbu rbu.exe
- rm -f srcck1 srcck1.exe
- rm -f fuzzershell fuzzershell.exe
- rm -f fuzzcheck fuzzcheck.exe
- rm -f sqldiff sqldiff.exe
- rm -f dbhash dbhash.exe
- rm -f fts5.* fts5parse.*
- rm -f threadtest5
- rm -f src-verify
- rm -f custom.rws
- rm -f has_tclsh84 has_tclsh85
+#
+# Vars with the AS_ prefix are specifically related to AutoSetup.
+#
+# AS_AUTO_DEF is the main configure script.
+#
+AS_AUTO_DEF = $(TOP)/auto.def
+#
+# Shell commands to re-run $(TOP)/configure with the same args it was
+# invoked with to produce this makefile.
+#
+AS_AUTORECONFIG = @SQLITE_AUTORECONFIG@
-distclean: clean
- rm -f sqlite_cfg.h config.log config.status libtool Makefile sqlcipher.pc \
- $(TESTPROGS)
+USE_AMALGAMATION ?= @USE_AMALGAMATION@
+LINK_TOOLS_DYNAMICALLY ?= @LINK_TOOLS_DYNAMICALLY@
+AMALGAMATION_GEN_FLAGS ?= --linemacros=@AMALGAMATION_LINE_MACROS@
#
-# Windows section
+# CFLAGS for sqlite3$(T.exe)
#
-dll: sqlite3.dll
+SHELL_OPT ?= @OPT_SHELL@
-REAL_LIBOBJ = $(LIBOBJ:%.lo=.libs/%.o)
+Makefile: $(TOP)/Makefile.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
-$(REAL_LIBOBJ): $(LIBOBJ)
+sqlite3.pc: $(TOP)/sqlite3.pc.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+install: install-pc # defined in main.mk
-sqlite3.def: $(REAL_LIBOBJ)
- echo 'EXPORTS' >sqlite3.def
- nm $(REAL_LIBOBJ) | grep ' T ' | grep ' _sqlite3_' \
- | sed 's/^.* _//' >>sqlite3.def
-
-sqlite3.dll: $(REAL_LIBOBJ) sqlite3.def
- $(TCC) -shared -o $@ sqlite3.def \
- -Wl,"--strip-all" $(REAL_LIBOBJ)
+sqlite_cfg.h: $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
#
# Fiddle app
#
+# EMCC_WRAPPER must refer to the genuine emcc binary, or a
+# call-compatible wrapper, e.g. $(TOP)/tool/emcc.sh. If it's empty,
+# build components requiring Emscripten will not build.
+#
+# Achtung: though _this_ makefile is POSIX-make compatible, the fiddle
+# build requires GNU make.
+#
+EMCC_WRAPPER = @EMCC_WRAPPER@
fiddle: sqlite3.c shell.c
- make -C ext/wasm fiddle emcc_opt=-Os
+ @if [ x = "x$(EMCC_WRAPPER)" ]; then \
+ echo "Emscripten SDK not found by configure. Cannot build fiddle." 1&>2; \
+ exit 1; \
+ fi
+ $(MAKE) -C ext/wasm fiddle emcc_opt=-Os
#
# Spell-checking for source comments
@@ -1649,14 +314,36 @@ fiddle: sqlite3.c shell.c
#
./custom.rws: ./tool/custom.txt
@echo 'Updating custom dictionary from tool/custom.txt'
- aspell --lang=en create master ./custom.rws < $<
-
+ aspell --lang=en create master ./custom.rws < ./tool/custom.txt
+# Note that jimsh does not work here:
+# https://github.com/msteveb/jimtcl/issues/319
misspell: ./custom.rws has_tclsh84
$(TCLSH_CMD) ./tool/spellsift.tcl ./src/*.c ./src/*.h ./src/*.in
+#
+# clean/distclean are mostly defined in main.mk. In this makefile we
+# perform cleanup known to be relevant to (only) the autosetup-driven
+# build.
+#
+#clean-autosetup:
+# -if [ -f ext/wasm/GNUmakefile ]; then \
+# gmake --no-print-directory --ignore-errors -C ext/wasm clean; \
+# fi >/dev/null 2>&1; true
+#clean: clean-autosetup
+
+distclean-autosetup: clean
+ rm -f sqlite_cfg.h config.log config.status config.defines.* Makefile sqlite3.pc
+ rm -f $(TOP)/tool/emcc.sh
+ rm -f libsqlite3*$(T.dll)
+ rm -f jimsh0*
+distclean: distclean-autosetup
+
#
# tool/version-info: a utility for emitting sqlite3 version info
# in various forms.
#
-version-info$(TEXE): $(TOP)/tool/version-info.c Makefile sqlite3.h
- $(LTLINK) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c
+version-info$(T.exe): $(TOP)/tool/version-info.c Makefile sqlite3.h
+ $(T.link) $(ST_OPT) -o $@ $(TOP)/tool/version-info.c
+
+IS_CROSS_COMPILING = @IS_CROSS_COMPILING@
+include $(TOP)/main.mk
diff --git a/Makefile.linux-gcc b/Makefile.linux-gcc
deleted file mode 100644
index fe7349ad46..0000000000
--- a/Makefile.linux-gcc
+++ /dev/null
@@ -1,109 +0,0 @@
-#!/usr/make
-#
-# Makefile for SQLITE
-#
-# This is a template makefile for SQLite. Most people prefer to
-# use the autoconf generated "configure" script to generate the
-# makefile automatically. But that does not work for everybody
-# and in every situation. If you are having problems with the
-# "configure" script, you might want to try this makefile as an
-# alternative. Create a copy of this file, edit the parameters
-# below and type "make".
-#
-
-#### The toplevel directory of the source tree. This is the directory
-# that contains this "Makefile.in" and the "configure.in" script.
-#
-TOP = ../sqlite
-
-#### C Compiler and options for use in building executables that
-# will run on the platform that is doing the build.
-#
-BCC = gcc -g -O0
-#BCC = /opt/ancic/bin/c89 -0
-
-#### If you want the SQLite library to be safe for use within a
-# multi-threaded program, then define the following macro
-# appropriately:
-#
-#THREADSAFE = -DTHREADSAFE=1
-THREADSAFE = -DTHREADSAFE=0
-
-#### Specify any extra linker options needed to make the library
-# thread safe
-#
-THREADLIB = -lpthread -lm -ldl
-#THREADLIB =
-
-#### Specify any extra libraries needed to access required functions.
-#
-#TLIBS = -lrt # fdatasync on Solaris 8
-TLIBS =
-
-#### Leave SQLITE_DEBUG undefined for maximum speed. Use SQLITE_DEBUG=1
-# to check for memory leaks. Use SQLITE_DEBUG=2 to print a log of all
-# malloc()s and free()s in order to track down memory leaks.
-#
-# SQLite uses some expensive assert() statements in the inner loop.
-# You can make the library go almost twice as fast if you compile
-# with -DNDEBUG=1
-#
-OPTS += -DSQLITE_DEBUG=1
-OPTS += -DSQLITE_ENABLE_WHERETRACE
-OPTS += -DSQLITE_ENABLE_SELECTTRACE
-
-#### The suffix to add to executable files. ".exe" for windows.
-# Nothing for unix.
-#
-#EXE = .exe
-EXE =
-
-#### C Compile and options for use in building executables that
-# will run on the target platform. This is usually the same
-# as BCC, unless you are cross-compiling.
-#
-TCC = gcc -O0
-#TCC = gcc -g -O0 -Wall
-#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
-#TCC = /opt/mingw/bin/i386-mingw32-gcc -O6
-#TCC = /opt/ansic/bin/c89 -O +z -Wl,-a,archive
-
-#### Tools used to build a static library.
-#
-AR = ar cr
-#AR = /opt/mingw/bin/i386-mingw32-ar cr
-RANLIB = ranlib
-#RANLIB = /opt/mingw/bin/i386-mingw32-ranlib
-
-MKSHLIB = gcc -shared
-SO = so
-SHPREFIX = lib
-# SO = dll
-# SHPREFIX =
-
-#### Extra compiler options needed for programs that use the TCL library.
-#
-TCL_FLAGS = -I/home/drh/tcl/include/tcl8.6
-
-#### Linker options needed to link against the TCL library.
-#
-#LIBTCL = -ltcl -lm -ldl
-LIBTCL = /home/drh/tcl/lib/libtcl8.6.a -lm -lpthread -ldl -lz
-
-#### Additional objects for SQLite library when TCL support is enabled.
-#TCLOBJ =
-TCLOBJ = tclsqlite.o
-
-#### Compiler options needed for programs that use the readline() library.
-#
-READLINE_FLAGS =
-#READLINE_FLAGS = -DHAVE_READLINE=1 -I/usr/include/readline
-
-#### Linker options needed by programs using readline() must link against.
-#
-LIBREADLINE =
-#LIBREADLINE = -static -lreadline -ltermcap
-
-# You should not have to change anything below this line
-###############################################################################
-include $(TOP)/main.mk
diff --git a/Makefile.linux-generic b/Makefile.linux-generic
new file mode 100644
index 0000000000..c7441fa517
--- /dev/null
+++ b/Makefile.linux-generic
@@ -0,0 +1,64 @@
+#!/usr/make
+all:
+#
+# Makefile for SQLITE
+#
+# This is a template makefile for SQLite. Most people prefer to
+# use the autoconf generated "configure" script to generate the
+# makefile automatically. But that does not work for everybody
+# and in every situation. If you are having problems with the
+# "configure" script, you might want to try this makefile as an
+# alternative. Create a copy of this file, edit the parameters
+# below and type "make".
+#
+# Maintenance note: because this is the template for Linux systems, it
+# is assumed that the platform has GNU make and this file takes
+# advantage of that.
+#
+####
+#
+# $(TOP) = The toplevel directory of the source tree. This is the
+# directory that contains "Makefile.in" and "auto.def".
+#
+TOP ?= $(realpath $(dir $(lastword $(MAKEFILE_LIST))))
+
+#
+# $(CFLAGS) will be used when compiling the library and most
+# utilities. It must normally contain -fPIC on Linux systems,
+# but overriding CFLAGS is an easy way for users to inadvertently
+# remove -fPIC from their builds, so we generally expect to see
+# -fPIC in $(CFLAGS.core), which main.mk will integrate with
+# the CFLAGS where needed.
+#
+CFLAGS =
+CFLAGS.core = -fPIC
+
+#
+# $(SHELL_OPT) contains CFLAGS for building the sqlite3 CLI shell.
+# See main.mk for other potentially-relevant vars which may need
+# tweaking, like $(LDFLAGS_READLINE).
+#
+SHELL_OPT += -DHAVE_READLINE=1
+SHELL_OPT += -DSQLITE_HAVE_ZLIB=1
+LDFLAGS.readline = -lreadline # may need -lcurses etc, depending on the system
+CFLAGS.readline = # needs -I... if readline.h is in an unusual place.
+LDFLAGS.zlib = -lz
+
+#
+# Library's version number.
+#
+PACKAGE_VERSION ?= $(shell cat $(TOP)/VERSION 2>/dev/null)
+
+# sqlite_cfg.h is typically created by the configure script. It's
+# commonly not needed but main.mk does not know that so we have to
+# create a dummy if we don't already have one.
+sqlite_cfg.h:
+ touch $@
+distclean-.:
+ rm -f sqlite_cfg.h
+
+#
+# With the above in place, we can now import the rules make use of
+# it...
+#
+include $(TOP)/main.mk
diff --git a/Makefile.msc b/Makefile.msc
index 85487315eb..951d3e1536 100644
--- a/Makefile.msc
+++ b/Makefile.msc
@@ -18,6 +18,15 @@ USE_AMALGAMATION = 1
!ENDIF
# <>
+# Optionally set EXTRA_SRC to a list of C files to append to
+# the generated sqlite3.c. Any sqlite3 extensions added this
+# way may require manual editing, as described in
+# https://sqlite.org/forum/forumpost/903f721f3e7c0d25
+#
+!IFNDEF EXTRA_SRC
+EXTRA_SRC =
+!ENDIF
+
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
@@ -59,6 +68,14 @@ USE_STDCALL = 0
USE_SEH = 1
!ENDIF
+# Use STATICALLY_LINK_TCL=1 to statically link against TCL
+#
+!IFNDEF STATICALLY_LINK_TCL
+STATICALLY_LINK_TCL = 0
+!ELSEIF $(STATICALLY_LINK_TCL)!=0
+CCOPTS = $(CCOPTS) -DSTATIC_BUILD
+!ENDIF
+
# Set this non-0 to have the shell executable link against the core dynamic
# link library.
#
@@ -372,6 +389,7 @@ SQLITE_TCL_DEP =
# the Windows platform.
#
!IFNDEF OPT_FEATURE_FLAGS
+OPT_FEATURE_FLAGS = $(OPT_XTRA)
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
@@ -385,6 +403,14 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
+# Additional feature-options above and beyond what are normally used can be
+# be added using OPTIONS=.... on the command-line. These values are
+# appended to the OPT_FEATURE_FLAGS variable.
+#
+!IFDEF OPTIONS
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) $(OPTIONS)
+!ENDIF
+
# Should the session extension be enabled? If so, add compilation options
# to enable it.
#
@@ -913,16 +939,28 @@ TCC = $(TCC) /fsanitize=address
# prior to running nmake in order to match the actual installed location and
# version on this machine.
#
-!IFNDEF TCLVERSION
-TCLVERSION = 86
+!IF $(STATICALLY_LINK_TCL)!=0
+TCLSUFFIX = s
!ENDIF
-
!IFNDEF TCLSUFFIX
TCLSUFFIX =
!ENDIF
!IFNDEF TCLDIR
-TCLDIR = $(TOP)\compat\tcl
+TCLDIR = C:\Tcl
+!ENDIF
+
+!IFNDEF TCLVERSION
+!IF EXISTS("$(TCLDIR)\lib\tcl90$(TCLSUFFIX).lib")
+TCLVERSION = 90
+!ELSEIF EXISTS("$(TCLDIR)\lib\tcl86$(TCLSUFFIX).lib")
+TCLVERSION = 86
+!ELSEIF EXISTS("$(TCLDIR)\lib\tcl86t.lib")
+TCLSUFFIX = t
+TCLVERSION = 86
+!ELSE
+TCLVERSION = 90
+!ENDIF
!ENDIF
!IFNDEF TCLINCDIR
@@ -937,8 +975,24 @@ TCLLIBDIR = $(TCLDIR)\lib
LIBTCL = tcl$(TCLVERSION)$(TCLSUFFIX).lib
!ENDIF
+!IFNDEF TCLLIBS
+!IF $(STATICALLY_LINK_TCL)!=0
+TCLLIBS = /NODEFAULTLIB:libucrt.lib netapi32.lib user32.lib ucrt.lib
+!ELSE
+TCLLIBS =
+!ENDIF
+!ENDIF
+
!IFNDEF LIBTCLSTUB
+!IF EXISTS("$(TCLLIBDIR)\tclstub$(TCLVERSION)$(TCLSUFFIX).lib")
LIBTCLSTUB = tclstub$(TCLVERSION)$(TCLSUFFIX).lib
+!ELSEIF EXISTS("$(TCLLIBDIR)\tclstub$(TCLSUFFIX).lib")
+LIBTCLSTUB = tclstub$(TCLSUFFIX).lib
+!ELSEIF EXISTS("$(TCLLIBDIR)\tclstub$(TCLVERSION).lib")
+LIBTCLSTUB = tclstub$(TCLVERSION).lib
+!ELSE
+LIBTCLSTUB = tclstub.lib
+!ENDIF
!ENDIF
!IFNDEF LIBTCLPATH
@@ -997,12 +1051,32 @@ LIBICU = icuuc.lib icuin.lib
# specific Tcl shell to use.
#
!IFNDEF TCLSH_CMD
-!IF $(USE_TCLSH_IN_PATH)!=0 || !EXIST("$(TCLDIR)\bin\tclsh.exe")
-TCLSH_CMD = tclsh
-!ELSE
+!IF EXISTS("$(TCLDIR)\bin\tclsh$(TCLVERSION).exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh$(TCLVERSION).exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh90.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh90.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh86.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh86.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh86t.exe")
+TCLSH_CMD = $(TCLDIR)\bin\tclsh86t.exe
+!ELSEIF EXISTS("$(TCLDIR)\bin\tclsh.exe")
TCLSH_CMD = $(TCLDIR)\bin\tclsh.exe
+!ELSE
+TCLSH_CMD = tclsh
!ENDIF
!ENDIF
+
+# A light-weight TCLSH replacement that can be used for code generation
+# but which is not adequate for testing. This is "jimsh0" by default,
+# with source code in the repository. To force the whole build to use
+# the full, official tclsh, add WITHOUT_JIMSH=1 to the nmake command line.
+#
+!IFDEF WITHOUT_JIMSH
+JIM_TCLSH = $(TCLSH_CMD)
+!ENDIF
+!IFNDEF JIM_TCLSH
+JIM_TCLSH = jimsh0.exe
+!ENDIF
# <>
# Compiler options needed for programs that use the readline() library.
@@ -1033,15 +1107,6 @@ RCC = $(RCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1
TLIBS =
!ENDIF
-# Flags controlling use of the in memory btree implementation
-#
-# SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
-# default to file, 2 to default to memory, and 3 to force temporary
-# tables to always be in memory.
-#
-TCC = $(TCC) -DSQLITE_TEMP_STORE=1
-RCC = $(RCC) -DSQLITE_TEMP_STORE=1
-
# Enable/disable loadable extensions, and other optional features
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
# The same set of OMIT and ENABLE flags should be passed to the
@@ -1320,13 +1385,11 @@ LIBRESOBJS =
# Core source code files, part 1.
#
SRC00 = \
- $(TOP)\src\crypto.c \
+ $(TOP)\src\sqlcipher.c \
$(TOP)\src\crypto_cc.c \
- $(TOP)\src\crypto_impl.c \
$(TOP)\src\crypto_libtomcrypt.c \
$(TOP)\src\crypto_nss.c \
$(TOP)\src\crypto_openssl.c \
- $(TOP)\src\crypto.h \
$(TOP)\src\sqlcipher.h \
$(TOP)\src\alter.c \
$(TOP)\src\analyze.c \
@@ -1525,7 +1588,6 @@ TESTSRC = \
$(TOP)\src\test8.c \
$(TOP)\src\test9.c \
$(TOP)\src\test_autoext.c \
- $(TOP)\src\test_async.c \
$(TOP)\src\test_backup.c \
$(TOP)\src\test_bestindex.c \
$(TOP)\src\test_blob.c \
@@ -1592,16 +1654,20 @@ TESTEXT = \
$(TOP)\ext\misc\percentile.c \
$(TOP)\ext\misc\prefixes.c \
$(TOP)\ext\misc\qpvtab.c \
+ $(TOP)\ext\misc\randomjson.c \
$(TOP)\ext\misc\regexp.c \
$(TOP)\ext\misc\remember.c \
$(TOP)\ext\misc\series.c \
$(TOP)\ext\misc\spellfix.c \
+ $(TOP)\ext\misc\stmtrand.c \
$(TOP)\ext\misc\totype.c \
$(TOP)\ext\misc\unionvtab.c \
$(TOP)\ext\misc\wholenumber.c \
$(TOP)\ext\rtree\test_rtreedoc.c \
$(TOP)\ext\recover\sqlite3recover.c \
$(TOP)\ext\recover\test_recover.c \
+ $(TOP)\ext\intck\test_intck.c \
+ $(TOP)\ext\intck\sqlite3intck.c \
$(TOP)\ext\recover\dbdata.c
# If use of zlib is enabled, add the "zipfile.c" source file.
@@ -1618,7 +1684,6 @@ TESTSRC2 = \
$(SRC01) \
$(SRC07) \
$(SRC10) \
- $(TOP)\ext\async\sqlite3async.c \
fts5.c
# Header files used by all library source files.
@@ -1700,6 +1765,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF
# <>
@@ -1736,6 +1802,8 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MMAP_SIZE=0
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_OMIT_LOAD_EXTENSION
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRIVATE=""
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STRICT_SUBTYPE=1
+FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_STATIC_RANDOMJSON
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_MAX_MEMORY=50000000
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_PRINTF_PRECISION_LIMIT=1000
@@ -1752,6 +1820,8 @@ FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\fuzzinvariants.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\test\vt02.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\dbdata.c
FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\recover\sqlite3recover.c
+FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\percentile.c
+FUZZCHECK_SRC = $(FUZZCHECK_SRC) $(TOP)\ext\misc\randomjson.c
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
DBFUZZ_COMPILE_OPTS = -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION
@@ -1792,6 +1862,11 @@ dll: $(SQLITE3DLL)
#
shell: $(SQLITE3EXE)
+# jimsh0 - replacement for tclsh
+#
+jimsh0.exe: $(TOP)\autosetup\jimsh0.c
+ cl -DHAVE__FULLPATH=1 $(TOP)\autosetup\jimsh0.c
+
# <>
libsqlite3.lib: $(LIBOBJ)
$(LTLIB) $(LTLIBOPTS) /OUT:$@ $(LIBOBJ) $(TLIBS)
@@ -1807,22 +1882,38 @@ tclsqlite3.def: tclsqlite.lo
pkgIndex.tcl: $(TOP)\VERSION
for /F %%V in ('type "$(TOP)\VERSION"') do ( \
- echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] sqlite3] \
+ echo package ifneeded sqlite3 @version@ [list load [file join $$dir $(SQLITE3TCLDLL)] Sqlite3] \
| $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact @version@ %%V > pkgIndex.tcl \
)
$(SQLITE3TCLDLL): libtclsqlite3.lib $(LIBRESOBJS) tclsqlite3.def pkgIndex.tcl
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL /DEF:tclsqlite3.def /OUT:$@ libtclsqlite3.lib $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
+
+tclextension: $(SQLITE3TCLDLL)
+
+tclextension-install: $(SQLITE3TCLDLL)
+ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --install-only
+
+tclextension-uninstall:
+ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --uninstall
+
+tclextension-list:
+ @ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --info
+
+tclextension-verify: sqlite3.h
+ @ $(TCLSH_CMD) $(TOP)\tool\buildtclext.tcl --version-check
+
+
# <>
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
# <>
-sqlite3.def: libsqlite3.lib
+sqlite3.def: libsqlite3.lib $(JIM_TCLSH)
echo EXPORTS > sqlite3.def
dumpbin /all libsqlite3.lib \
- | $(TCLSH_CMD) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \
+ | $(JIM_TCLSH) $(TOP)\tool\replace.tcl include "^\s+1 _?(sqlite3(?:session|changeset|changegroup|rebaser|rbu)?_[^@]*)(?:@\d+)?$$" \1 \
| sort >> sqlite3.def
# <>
@@ -1831,12 +1922,25 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
# <>
-sqldiff.exe: $(TOP)\tool\sqldiff.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
- $(LTLINK) $(NO_WARN) $(TOP)\tool\sqldiff.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
+sqldiff.exe: $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
+ $(LTLINK) $(NO_WARN) -I$(TOP)\ext\misc $(TOP)\tool\sqldiff.c $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
dbhash.exe: $(TOP)\tool\dbhash.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\tool\dbhash.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+RSYNC_SRC = \
+ $(TOP)\tool\sqlite3_rsync.c \
+ $(SQLITE3C)
+
+RSYNC_OPT = \
+ -DSQLITE_ENABLE_DBPAGE_VTAB \
+ -DSQLITE_THREADSAFE=0 \
+ -DSQLITE_OMIT_LOAD_EXTENSION \
+ -DSQLITE_OMIT_DEPRECATED
+
+sqlite3_rsync.exe: $(RSYNC_SRC) $(LIBRESOBJS)
+ $(LTLINK) $(RSYNC_OPT) $(NO_WARN) $(RSYNC_SRC) /link $(LDFLAGS) $(LTLINKOPTS) $(LIBRESOBJS)
+
scrub.exe: $(TOP)\ext\misc\scrub.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) -DSCRUB_STANDALONE=1 $(TOP)\ext\misc\scrub.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -1864,6 +1968,10 @@ fuzzcheck.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
fuzzcheck-asan.exe: $(FUZZCHECK_SRC) $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) /fsanitize=address $(FUZZCHECK_OPTS) $(FUZZCHECK_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+run-fuzzcheck: fuzzcheck.exe fuzzcheck-asan.exe
+ fuzzcheck --spinner $(FUZZDB)
+ fuzzcheck-asan --spinner $(FUZZDB)
+
ossshell.exe: $(OSSSHELL_SRC) $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(FUZZCHECK_OPTS) $(OSSSHELL_SRC) $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
@@ -1893,33 +2001,22 @@ mptest: mptester.exe
# files are automatically generated. This target takes care of
# all that automatic generation.
#
-.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c $(SQLITE_TCL_DEP)
+.target_source: $(SRC) $(TOP)\tool\vdbe-compress.tcl fts5.c $(SQLITE_TCL_DEP) $(JIM_TCLSH)
-rmdir /Q/S tsrc 2>NUL
-mkdir tsrc
- for %i in ($(SRC00)) do copy /Y %i tsrc
- for %i in ($(SRC01)) do copy /Y %i tsrc
- for %i in ($(SRC03)) do copy /Y %i tsrc
- for %i in ($(SRC04)) do copy /Y %i tsrc
- for %i in ($(SRC05)) do copy /Y %i tsrc
- for %i in ($(SRC07)) do copy /Y %i tsrc
- for %i in ($(SRC09)) do copy /Y %i tsrc
- for %i in ($(SRC10)) do copy /Y %i tsrc
- for %i in ($(SRC11)) do copy /Y %i tsrc
- for %i in ($(SRC12)) do copy /Y %i tsrc
- copy /Y fts5.c tsrc
+ $(JIM_TCLSH) $(TOP)\tool\cp.tcl $(SRC00) $(SRC01) $(SRC03) $(SRC04) $(SRC05) $(SRC07) $(SRC09) $(SRC10) $(SRC11) $(SRC12) fts5.c fts5.h tsrc
copy /B tsrc\fts5.c +,,
- copy /Y fts5.h tsrc
copy /B tsrc\fts5.h +,,
del /Q tsrc\sqlite.h.in tsrc\parse.y 2>NUL
- $(TCLSH_CMD) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
+ $(JIM_TCLSH) $(TOP)\tool\vdbe-compress.tcl $(OPTS) < tsrc\vdbe.c > vdbe.new
move vdbe.new tsrc\vdbe.c
echo > .target_source
-sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe
- $(TCLSH_CMD) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS)
+sqlite3.c: .target_source sqlite3ext.h sqlite3session.h $(MKSQLITE3C_TOOL) src-verify.exe $(JIM_TCLSH)
+ $(JIM_TCLSH) $(MKSQLITE3C_TOOL) $(MKSQLITE3C_ARGS) $(EXTRA_SRC)
-sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl
- $(TCLSH_CMD) $(TOP)\tool\split-sqlite3c.tcl
+sqlite3-all.c: sqlite3.c $(TOP)\tool\split-sqlite3c.tcl $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\tool\split-sqlite3c.tcl
# <>
# Rule to build the amalgamation
@@ -1961,11 +2058,11 @@ opcodes.lo: opcodes.c
#
!IF $(USE_RC)!=0
# <>
-$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H) $(TOP)\VERSION
+$(LIBRESOBJS): $(TOP)\src\sqlite3.rc $(SQLITE3H) $(TOP)\VERSION $(JIM_TCLSH)
echo #ifndef SQLITE_RESOURCE_VERSION > sqlite3rc.h
for /F %%V in ('type "$(TOP)\VERSION"') do ( \
echo #define SQLITE_RESOURCE_VERSION %%V \
- | $(TCLSH_CMD) $(TOP)\tool\replace.tcl exact . ^, >> sqlite3rc.h \
+ | $(JIM_TCLSH) $(TOP)\tool\replace.tcl exact . ^, >> sqlite3rc.h \
)
echo #endif >> sqlite3rc.h
$(LTRCOMPILE) -fo $(LIBRESOBJS) $(TOP)\src\sqlite3.rc
@@ -2226,11 +2323,11 @@ tclsqlite3.exe: tclsqlite-shell.lo $(SQLITE3C) $(SQLITE3H) $(LIBRESOBJS)
# Rules to build opcodes.c and opcodes.h
#
-opcodes.c: opcodes.h $(TOP)\tool\mkopcodec.tcl
- $(TCLSH_CMD) $(TOP)\tool\mkopcodec.tcl opcodes.h > opcodes.c
+opcodes.c: opcodes.h $(TOP)\tool\mkopcodec.tcl $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\tool\mkopcodec.tcl opcodes.h > opcodes.c
-opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl
- type parse.h $(TOP)\src\vdbe.c | $(TCLSH_CMD) $(TOP)\tool\mkopcodeh.tcl > opcodes.h
+opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl $(JIM_TCLSH)
+ type parse.h $(TOP)\src\vdbe.c | $(JIM_TCLSH) $(TOP)\tool\mkopcodeh.tcl > opcodes.h
# Rules to build parse.c and parse.h - the outputs of lemon.
#
@@ -2242,8 +2339,8 @@ parse.c: $(TOP)\src\parse.y lemon.exe
copy /B parse.y +,,
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) -S parse.y
-$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
- $(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
+$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\tool\mksqlite3h.tcl "$(TOP:\=/)" -o $(SQLITE3H) $(MKSQLITE3H_ARGS)
sqlite3ext.h: .target_source
!IF $(USE_STDCALL)!=0 || $(FOR_WIN10)!=0
@@ -2266,40 +2363,48 @@ mkkeywordhash.exe: $(TOP)\tool\mkkeywordhash.c
keywordhash.h: $(TOP)\tool\mkkeywordhash.c mkkeywordhash.exe
.\mkkeywordhash.exe > keywordhash.h
-# Source files that go into making shell.c
-SHELL_SRC = \
- $(TOP)\src\shell.c.in \
- $(TOP)\ext\consio\console_io.c \
- $(TOP)\ext\consio\console_io.h \
- $(TOP)\ext\misc\appendvfs.c \
- $(TOP)\ext\misc\completion.c \
- $(TOP)\ext\misc\base64.c \
- $(TOP)\ext\misc\base85.c \
- $(TOP)\ext\misc\decimal.c \
- $(TOP)\ext\misc\fileio.c \
- $(TOP)\ext\misc\ieee754.c \
- $(TOP)\ext\misc\regexp.c \
- $(TOP)\ext\misc\series.c \
- $(TOP)\ext\misc\shathree.c \
- $(TOP)\ext\misc\uint.c \
- $(TOP)\ext\expert\sqlite3expert.c \
- $(TOP)\ext\expert\sqlite3expert.h \
- $(TOP)\ext\misc\memtrace.c \
- $(TOP)\ext\misc\pcachetrace.c \
- $(TOP)\ext\recover\dbdata.c \
- $(TOP)\ext\recover\sqlite3recover.c \
- $(TOP)\ext\recover\sqlite3recover.h \
- $(TOP)\src\test_windirent.c
+# Source and header files that shell.c depends on
+SHELL_DEP = \
+ $(TOP)\src\shell.c.in \
+ $(TOP)\ext\expert\sqlite3expert.c \
+ $(TOP)\ext\expert\sqlite3expert.h \
+ $(TOP)\ext\intck\sqlite3intck.c \
+ $(TOP)\ext\intck\sqlite3intck.h \
+ $(TOP)\ext\misc\appendvfs.c \
+ $(TOP)\ext\misc\base64.c \
+ $(TOP)\ext\misc\base85.c \
+ $(TOP)\ext\misc\completion.c \
+ $(TOP)\ext\misc\decimal.c \
+ $(TOP)\ext\misc\fileio.c \
+ $(TOP)\ext\misc\ieee754.c \
+ $(TOP)\ext\misc\memtrace.c \
+ $(TOP)\ext\misc\pcachetrace.c \
+ $(TOP)\ext\misc\percentile.c \
+ $(TOP)\ext\misc\regexp.c \
+ $(TOP)\ext\misc\series.c \
+ $(TOP)\ext\misc\sha1.c \
+ $(TOP)\ext\misc\shathree.c \
+ $(TOP)\ext\misc\sqlar.c \
+ $(TOP)\ext\misc\sqlite3_stdio.c \
+ $(TOP)\ext\misc\sqlite3_stdio.h \
+ $(TOP)\ext\misc\uint.c \
+ $(TOP)\ext\misc\vfstrace.c \
+ $(TOP)\ext\misc\zipfile.c \
+ $(TOP)\ext\recover\dbdata.c \
+ $(TOP)\ext\recover\sqlite3recover.c \
+ $(TOP)\ext\recover\sqlite3recover.h \
+ $(TOP)\src\test_windirent.c \
+ $(TOP)\src\test_windirent.h
# If use of zlib is enabled, add the "zipfile.c" source file.
#
!IF $(USE_ZLIB)!=0
-SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\sqlar.c
-SHELL_SRC = $(SHELL_SRC) $(TOP)\ext\misc\zipfile.c
+SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\sqlar.c
+SHELL_DEP = $(SHELL_DEP) $(TOP)\ext\misc\zipfile.c
!ENDIF
-shell.c: $(SHELL_SRC) $(TOP)\tool\mkshellc.tcl
- $(TCLSH_CMD) $(TOP)\tool\mkshellc.tcl > shell.c
+shell.c: $(SHELL_DEP) $(TOP)\tool\mkshellc.tcl $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\tool\mkshellc.tcl shell.c
zlib:
pushd $(ZLIBDIR) && $(MAKE) /f win32\Makefile.msc clean $(ZLIBLIB) && popd
@@ -2402,13 +2507,13 @@ fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
fts5parse.h: fts5parse.c
-fts5.c: $(FTS5_SRC)
- $(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
+fts5.c: $(FTS5_SRC) $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\ext\fts5\tool\mkfts5c.tcl
copy /Y $(TOP)\ext\fts5\fts5.h .
copy /B fts5.h +,,
-lsm1.c: $(LSM1_SRC)
- $(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
+lsm1.c: $(LSM1_SRC) $(JIM_TCLSH)
+ $(JIM_TCLSH) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
copy /Y $(TOP)\ext\lsm1\lsm.h .
copy /B lsm.h +,,
@@ -2441,6 +2546,8 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_CKSUMVFS_STATIC=1
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
+TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STATIC_RANDOMJSON
+TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_STRICT_SUBTYPE=1
TESTFIXTURE_SRC0 = $(TESTEXT) $(TESTSRC2)
TESTFIXTURE_SRC1 = $(TESTEXT) $(SQLITE3C)
@@ -2480,12 +2587,12 @@ extensiontest: testfixture.exe testloadext.dll
@set PATH=$(LIBTCLPATH);$(PATH)
.\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS)
-tool-zip: testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe $(TOP)\tool\mktoolzip.tcl
+tool-zip: testfixture.exe sqlite3.exe sqldiff.exe sqlite3_analyzer.exe sqlite3_rsync.exe $(TOP)\tool\mktoolzip.tcl
.\testfixture.exe $(TOP)\tool\mktoolzip.tcl
-coretestprogs: $(TESTPROGS)
+coretestprogs: testfixture.exe sqlite3.exe
-testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe
+testprogs: $(TESTPROGS) srcck1.exe fuzzcheck.exe sessionfuzz.exe
fulltest: alltest fuzztest
@@ -2508,6 +2615,13 @@ queryplantest: testfixture.exe shell
fuzztest: fuzzcheck.exe
.\fuzzcheck.exe $(FUZZDATA)
+# Legacy testing target for third-party integrators. The SQLite
+# developers seldom use this target themselves. Instead
+# they use "nmake /f Makefile.msc devtest" which runs tests on
+# a standard set of options
+#
+test: $(TESTPROGS) sourcetest fuzztest tcltest
+
# Minimal testing that runs in less than 3 minutes (on a fast machine)
#
quicktest: testfixture.exe sourcetest
@@ -2517,7 +2631,6 @@ quicktest: testfixture.exe sourcetest
# This is the common case. Run many tests that do not take too long,
# including fuzzcheck, sqlite3_analyzer, and sqldiff tests.
#
-test: $(TESTPROGS) sourcetest fuzztest tcltest
# The veryquick.test TCL tests.
#
@@ -2531,17 +2644,27 @@ tcltest: testfixture.exe
testrunner: testfixture.exe
.\testfixture.exe $(TOP)\test\testrunner.tcl
-# Runs both fuzztest and testrunner, consecutively.
+# This is the testing target preferred by the core SQLite developers.
+# It runs tests under a standard configuration. The devs run
+# "nmake /f Makefile.msc devtest" prior to each check-in, at a minimum.
+# Probably other tests too, but at least this one.
#
-devtest: testfixture.exe fuzztest testrunner
+devtest: srctree-check sourcetest
+ $(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
mdevtest:
$(TCLSH_CMD) $(TOP)\test\testrunner.tcl mdevtest
+# Validate that various generated files in the source tree
+# are up-to-date.
+#
+srctree-check: $(TOP)\tool\srctree-check.tcl
+ $(TCLSH_CMD) $(TOP)\tool\srctree-check.tcl
+
# Testing for a release
#
-releasetest: testfixture.exe fuzztest
- testfixture.exe $(TOP)\test\testrunner.tcl release
+releasetest:
+ $(TCLSH_CMD) $(TOP)\test\testrunner.tcl release
smoketest: $(TESTPROGS)
@@ -2551,8 +2674,8 @@ smoketest: $(TESTPROGS)
shelltest: $(TESTPROGS)
.\testfixture.exe $(TOP)\test\permutations.test shell
-sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(SQLITE_TCL_DEP)
- $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in > $@
+sqlite3_analyzer.c: $(SQLITE3C) $(SQLITE3H) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl $(TOP)\tool\mkccode.tcl $(TOP)\tool\sqlite3_analyzer.c.in $(TOP)\ext\misc\sqlite3_stdio.h $(TOP)\ext\misc\sqlite3_stdio.c $(SQLITE_TCL_DEP)
+ $(TCLSH_CMD) $(TOP)\tool\mkccode.tcl -DINCLUDE_SQLITE3_C $(TOP)\tool\sqlite3_analyzer.c.in > $@
sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
@@ -2673,6 +2796,18 @@ THREADTEST3_SRC = \
threadtest3.exe: $(THREADTEST3_SRC) $(TOP)\src\test_multiplex.c $(SQLITE3C) $(SQLITE3H)
$(LTLINK) $(NO_WARN) $(TOP)\test\threadtest3.c $(TOP)\src\test_multiplex.c $(SQLITE3C) /link $(LDFLAGS) $(LTLINKOPTS)
+# Display key variables that control which version of TCL is to be used.
+#
+tcl-env:
+ @echo TCLDIR = $(TCLDIR)
+ @echo TCLVERSION = $(TCLVERSION)
+ @echo TCLSUFFIX = $(TCLSUFFIX)
+ @echo LIBTCL = $(LIBTCL)
+ @echo LIBTCLSTUB = $(LIBTCLSTUB)
+ @echo TCLSH_CMD = $(TCLSH_CMD)
+ @echo JIM_TCLSH = $(JIM_TCLSH)
+ @echo VISUALSTUDIOVERSION = $(VISUALSTUDIOVERSION)
+
LSMDIR=$(TOP)\ext\lsm1
!INCLUDE $(LSMDIR)\Makefile.msc
@@ -2682,7 +2817,8 @@ moreclean: clean
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
- del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q sqlite3.def tclsqlite3.def 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
# <>
del /Q $(SQLITE3TCLDLL) pkgIndex.tcl 2>NUL
@@ -2706,7 +2842,7 @@ clean:
del /Q sqlite3.c sqlite3-*.c sqlite3.h 2>NUL
del /Q sqlite3rc.h 2>NUL
del /Q shell.c sqlite3ext.h sqlite3session.h 2>NUL
- del /Q sqlite3_analyzer.exe sqlite3_analyzer.c 2>NUL
+ del /Q sqlite3_analyzer.exe sqlite3_analyzer.c sqlite3_rsync.exe 2>NUL
del /Q sqlite-*-output.vsix 2>NUL
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
del /Q sqltclsh.* 2>NUL
diff --git a/README.md b/README.md
index 181b0289d7..2fa46ecc64 100644
--- a/README.md
+++ b/README.md
@@ -17,8 +17,7 @@ SQLCipher is maintained by Zetetic, LLC, and additional information and document
- 100% of data in the database file is encrypted
- Good security practices (CBC mode, HMAC, key derivation)
- Zero-configuration and application level cryptography
-- Algorithms provided by the peer reviewed OpenSSL crypto library.
-- Configurable crypto providers
+- Support for multiple cryptographic providers
## Compatibility
@@ -32,26 +31,18 @@ The SQLCipher team welcomes contributions to the core library. All contributions
## Compiling
-Building SQLCipher is similar to compiling a regular version of SQLite from source, with a couple of small exceptions:
+Building SQLCipher is similar to compiling a regular version of SQLite from source, with a few small exceptions. You must:
- 1. You *must* define `SQLITE_HAS_CODEC` and either `SQLITE_TEMP_STORE=2` or `SQLITE_TEMP_STORE=3`
- 2. You will need to link against a support cryptographic provider (OpenSSL, LibTomCrypt, CommonCrypto/Security.framework, or NSS)
+ 1. define `SQLITE_HAS_CODEC`
+ 2. define `SQLITE_TEMP_STORE=2` or `SQLITE_TEMP_STORE=3` (or use `configure`'s --with-tempstore=yes option)
+ 3. define `SQLITE_EXTRA_INIT=sqlcipher_extra_init` and `SQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown`
+ 4. define `SQLITE_THREADSAFE` to `1` or `2` (enabled automatically by `configure`)
+ 2. compile and link with a supported cryptographic provider (OpenSSL, LibTomCrypt, CommonCrypto/Security.framework, or NSS)
-The following examples demonstrate linking against OpenSSL, which is a readily available provider on most Unix-like systems.
-
-Example 1. Static linking (replace /opt/local/lib with the path to libcrypto.a). Note in this
-example, `--enable-tempstore=yes` is setting `SQLITE_TEMP_STORE=2` for the build.
-
-```
-$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \
- LDFLAGS="/opt/local/lib/libcrypto.a"
-$ make
-```
-
-Example 2. Dynamic linking
+The following examples demonstrate use of OpenSSL, which is a readily available provider on most Unix-like systems. Note that, in this example, `--with-tempstore=yes` is setting `SQLITE_TEMP_STORE=2` for the build, and `SQLITE_THREADSAFE` has a default value of `1`.
```
-$ ./configure --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" \
+$ ./configure --with-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_EXTRA_INIT=sqlcipher_extra_init -DSQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown" \
LDFLAGS="-lcrypto"
$ make
```
@@ -65,7 +56,7 @@ As a result, the SQLCipher package includes it's own independent tests that exer
To run SQLCipher specific tests, configure as described here and run the following to execute the tests and receive a report of the results:
```
-$ ./configure --enable-tempstore=yes --enable-fts5 CFLAGS="-DSQLITE_HAS_CODEC -DSQLCIPHER_TEST" \
+$ ./configure --with-tempstore=yes --enable-fts5 CFLAGS="-DSQLITE_HAS_CODEC -DSQLITE_EXTRA_INIT=sqlcipher_extra_init -DSQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown -DSQLCIPHER_TEST" \
LDFLAGS="-lcrypto"
$ make testfixture
$ ./testfixture test/sqlcipher.test
@@ -133,7 +124,7 @@ support@zetetic.net!
## Community Edition Open Source License
-Copyright (c) 2020, ZETETIC LLC
+Copyright (c) 2025, ZETETIC LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -163,14 +154,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SQLite Source Repository
This repository contains the complete source code for the
-[SQLite database engine](https://sqlite.org/). Some test scripts
-are also included. However, many other test scripts
+[SQLite database engine](https://sqlite.org/), including
+many test scripts. However, other test scripts
and most of the documentation are managed separately.
+See the [on-line documentation](https://sqlite.org/) for more information
+about what SQLite is and how it works from a user's perspective. This
+README file is about the source code that goes into building SQLite,
+not about how SQLite is used.
+
## Version Control
SQLite sources are managed using
-[Fossil](https://www.fossil-scm.org/), a distributed version control system
+[Fossil](https://fossil-scm.org/), a distributed version control system
that was specifically designed and written to support SQLite development.
The [Fossil repository](https://sqlite.org/src/timeline) contains the urtext.
@@ -230,24 +226,26 @@ archives or [SQLite archives](https://sqlite.org/cli.html#sqlar) as follows:
then click on the "Tarball" or "ZIP Archive" links on the information
page.
-If you do want to use Fossil to check out the source tree,
+To access sources directly using [Fossil](https://fossil-scm.org/home),
first install Fossil version 2.0 or later.
-(Source tarballs and precompiled binaries available
-[here](https://www.fossil-scm.org/fossil/uv/download.html). Fossil is
+Source tarballs and precompiled binaries available at
+. Fossil is
a stand-alone program. To install, simply download or build the single
-executable file and put that file someplace on your $PATH.)
+executable file and put that file someplace on your $PATH.
Then run commands like this:
- mkdir -p ~/sqlite ~/Fossils
+ mkdir -p ~/sqlite
cd ~/sqlite
- fossil clone https://www.sqlite.org/src ~/Fossils/sqlite.fossil
- fossil open ~/Fossils/sqlite.fossil
+ fossil open https://sqlite.org/src
-After setting up a repository using the steps above, you can always
-update to the latest version using:
+The "fossil open" command will take two or three minutes. Afterwards,
+you can do fast, bandwidth-efficient updates to the whatever versions
+of SQLite you like. Some examples:
- fossil update trunk ;# latest trunk check-in
- fossil update release ;# latest official release
+ fossil update trunk ;# latest trunk check-in
+ fossil update release ;# latest official release
+ fossil update trunk:2024-01-01 ;# First trunk check-in after 2024-01-01
+ fossil update version-3.39.0 ;# Version 3.39.0
Or type "fossil ui" to get a web-based user interface.
@@ -261,15 +259,42 @@ script found at the root of the source tree. Then run "make".
For example:
- tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
- mkdir bld ;# Build will occur in a sibling directory
- cd bld ;# Change to the build directory
- ../sqlite/configure ;# Run the configure script
- make ;# Builds the "sqlite3" command-line tool
- make sqlite3.c ;# Build the "amalgamation" source file
- make devtest ;# Run some tests (requires Tcl)
+ apt install gcc make tcl-dev ;# Make sure you have all the necessary build tools
+ tar xzf sqlite.tar.gz ;# Unpack the source tree into "sqlite"
+ mkdir bld ;# Build will occur in a sibling directory
+ cd bld ;# Change to the build directory
+ ../sqlite/configure ;# Run the configure script
+ make sqlite3 ;# Builds the "sqlite3" command-line tool
+ make sqlite3.c ;# Build the "amalgamation" source file
+ make sqldiff ;# Builds the "sqldiff" command-line tool
+ # Makefile targets below this point require tcl-dev
+ make tclextension-install ;# Build and install the SQLite TCL extension
+ make devtest ;# Run development tests
+ make releasetest ;# Run full release tests
+ make sqlite3_analyzer ;# Builds the "sqlite3_analyzer" tool
+
+See the makefile for additional targets. For debugging builds, the
+core developers typically run "configure" with options like this:
-See the makefile for additional targets.
+ ../sqlite/configure --enable-all --enable-debug CFLAGS='-O0 -g'
+
+For release builds, the core developers usually do:
+
+ ../sqlite/configure --enable-all
+
+Almost all makefile targets require a "tclsh" TCL interpreter version 8.6 or
+later. The "tclextension-install" target and the test targets that follow
+all require TCL development libraries too. ("apt install tcl-dev"). It is
+helpful, but is not required, to install the SQLite TCL extension (the
+"tclextension-install" target) prior to running tests. The "releasetest"
+target has additional requiremenst, such as "valgrind".
+
+On "make" command-lines, one can add "OPTIONS=..." to specify additional
+compile-time options over and above those set by ./configure. For example,
+to compile with the SQLITE_OMIT_DEPRECATED compile-time option, one could say:
+
+ ./configure --enable-all
+ make OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3
The configure script uses autoconf 2.61 and libtool. If the configure
script does not work out for you, there is a generic makefile named
@@ -279,7 +304,7 @@ show what changes are needed.
## Compiling for Windows Using MSVC
-On Windows, all applicable build products can be compiled with MSVC.
+On Windows, everything can be compiled with MSVC.
You will also need a working installation of TCL.
See the [compile-for-windows.md](doc/compile-for-windows.md) document for
additional information about how to install MSVC and TCL and configure your
@@ -290,48 +315,72 @@ TCL library, using a command like this:
set TCLDIR=c:\Tcl
-SQLite uses "tclsh.exe" as part of the build process, and so that utility
-program will need to be somewhere on your %PATH%. The finished SQLite library
-does not contain any TCL code, but it does use TCL to help with the build process
-and to run tests.
+SQLite uses "tclsh.exe" as part of the build process, and so that
+program will need to be somewhere on your %PATH%. SQLite itself
+does not contain any TCL code, but it does use TCL to help with the
+build process and to run tests. You may need to install TCL development
+libraries in order to successfully complete some makefile targets.
+It is helpful, but is not required, to install the SQLite TCL extension
+(the "tclextension-install" target) prior to running tests.
Build using Makefile.msc. Example:
- nmake /f Makefile.msc
+ nmake /f Makefile.msc sqlite3.exe
nmake /f Makefile.msc sqlite3.c
+ nmake /f Makefile.msc sqldiff.exe
+ # Makefile targets below this point require TCL development libraries
+ nmake /f Makefile.msc tclextension-install
nmake /f Makefile.msc devtest
nmake /f Makefile.msc releasetest
+ nmake /f Makefile.msc sqlite3_analyzer.exe
There are many other makefile targets. See comments in Makefile.msc for
details.
-## Source Code Tour
-
-Most of the core source files are in the **src/** subdirectory. The
-**src/** folder also contains files used to build the "testfixture" test
-harness. The names of the source files used by "testfixture" all begin
-with "test".
-The **src/** also contains the "shell.c" file
-which is the main program for the "sqlite3.exe"
-[command-line shell](https://sqlite.org/cli.html) and
-the "tclsqlite.c" file which implements the
-[Tcl bindings](https://sqlite.org/tclsqlite.html) for SQLite.
-(Historical note: SQLite began as a Tcl
-extension and only later escaped to the wild as an independent library.)
-
-Test scripts and programs are found in the **test/** subdirectory.
-Additional test code is found in other source repositories.
-See [How SQLite Is Tested](http://www.sqlite.org/testing.html) for
-additional information.
-
-The **ext/** subdirectory contains code for extensions. The
-Full-text search engine is in **ext/fts3**. The R-Tree engine is in
-**ext/rtree**. The **ext/misc** subdirectory contains a number of
-smaller, single-file extensions, such as a REGEXP operator.
-
-The **tool/** subdirectory contains various scripts and programs used
-for building generated source code files or for testing or for generating
-accessory programs such as "sqlite3_analyzer(.exe)".
+As with the unix Makefile, the OPTIONS=... argument can be passed on the nmake
+command-line to enable new compile-time options. For example:
+
+ nmake /f Makefile.msc OPTIONS=-DSQLITE_OMIT_DEPRECATED sqlite3.exe
+
+## Source Tree Map
+
+ * **src/** - This directory contains the primary source code for the
+ SQLite core. For historical reasons, C-code used for testing is
+ also found here. Source files intended for testing begin with "`test`".
+ The `tclsqlite3.c` and `tclsqlite3.h` files are the TCL interface
+ for SQLite and are also not part of the core.
+
+ * **test/** - This directory and its subdirectories contains code used
+ for testing. Files that end in "`.test`" are TCL scripts that run
+ tests using an augmented TCL interpreter named "testfixture". Use
+ a command like "`make testfixture`" (unix) or
+ "`nmake /f Makefile.msc testfixture.exe`" (windows) to build that
+ augmented TCL interpreter, then run individual tests using commands like
+ "`testfixture test/main.test`". This test/ subdirectory also contains
+ additional C code modules and scripts for other kinds of testing.
+
+ * **tool/** - This directory contains programs and scripts used to
+ build some of the machine-generated code that goes into the SQLite
+ core, as well as to build and run tests and perform diagnostics.
+ The source code to [the Lemon parser generator](./doc/lemon.html) is
+ found here. There are also TCL scripts used to build and/or transform
+ source code files. For example, the tool/mksqlite3h.tcl script reads
+ the src/sqlite.h.in file and uses it as a template to construct
+ the deliverable "sqlite3.h" file that defines the SQLite interface.
+
+ * **ext/** - Various extensions to SQLite are found under this
+ directory. For example, the FTS5 subsystem is in "ext/fts5/".
+ Some of these extensions (ex: FTS3/4, FTS5, RTREE) might get built
+ into the SQLite amalgamation, but not all of them. The
+ "ext/misc/" subdirectory contains an assortment of one-file extensions,
+ many of which are omitted from the SQLite core, but which are included
+ in the [SQLite CLI](https://sqlite.org/cli.html).
+
+ * **doc/** - Some documentation files about SQLite internals are found
+ here. Note, however, that the primary documentation designed for
+ application developers and users of SQLite is in a completely separate
+ repository. Note also that the primary API documentation is derived
+ from specially constructed comments in the src/sqlite.h.in file.
### Generated Source Code Files
@@ -345,7 +394,7 @@ manually-edited files and automatically-generated files.
The SQLite interface is defined by the **sqlite3.h** header file, which is
generated from src/sqlite.h.in, ./manifest.uuid, and ./VERSION. The
-[Tcl script](http://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
+[Tcl script](https://www.tcl.tk) at tool/mksqlite3h.tcl does the conversion.
The manifest.uuid file contains the SHA3 hash of the particular check-in
and is used to generate the SQLITE\_SOURCE\_ID macro. The VERSION file
contains the current SQLite version number. The sqlite3.h header is really
@@ -412,33 +461,39 @@ individual source file exceeds 32K lines in length.
## How It All Fits Together
SQLite is modular in design.
-See the [architectural description](http://www.sqlite.org/arch.html)
+See the [architectural description](https://www.sqlite.org/arch.html)
for details. Other documents that are useful in
-(helping to understand how SQLite works include the
-[file format](http://www.sqlite.org/fileformat2.html) description,
-the [virtual machine](http://www.sqlite.org/opcode.html) that runs
+helping to understand how SQLite works include the
+[file format](https://www.sqlite.org/fileformat2.html) description,
+the [virtual machine](https://www.sqlite.org/opcode.html) that runs
prepared statements, the description of
-[how transactions work](http://www.sqlite.org/atomiccommit.html), and
-the [overview of the query planner](http://www.sqlite.org/optoverview.html).
+[how transactions work](https://www.sqlite.org/atomiccommit.html), and
+the [overview of the query planner](https://www.sqlite.org/optoverview.html).
-Years of effort have gone into optimizing SQLite, both
+Decades of effort have gone into optimizing SQLite, both
for small size and high performance. And optimizations tend to result in
complex code. So there is a lot of complexity in the current SQLite
implementation. It will not be the easiest library in the world to hack.
-Key files:
+### Key source code files
* **sqlite.h.in** - This file defines the public interface to the SQLite
library. Readers will need to be familiar with this interface before
- trying to understand how the library works internally.
+ trying to understand how the library works internally. This file is
+ really a template that is transformed into the "sqlite3.h" deliverable
+ using a script invoked by the makefile.
* **sqliteInt.h** - this header file defines many of the data objects
used internally by SQLite. In addition to "sqliteInt.h", some
- subsystems have their own header files.
+ subsystems inside of sQLite have their own header files. These internal
+ interfaces are not for use by applications. They can and do change
+ from one release of SQLite to the next.
* **parse.y** - This file describes the LALR(1) grammar that SQLite uses
to parse SQL statements, and the actions that are taken at each step
- in the parsing process.
+ in the parsing process. The file is processed by the
+ [Lemon Parser Generator](./doc/lemon.html) to produce the actual C code
+ used for parsing.
* **vdbe.c** - This file implements the virtual machine that runs
prepared statements. There are various helper files whose names
@@ -481,6 +536,11 @@ Key files:
(and some other test programs too) is built and run when you type
"make test".
+ * **VERSION**, **manifest**, and **manifest.uuid** - These files define
+ the current SQLite version number. The "VERSION" file is human generated,
+ but the "manifest" and "manifest.uuid" files are automatically generated
+ by the [Fossil version control system](https://fossil-scm.org/).
+
There are many other source files. Each has a succinct header comment that
describes its purpose and role within the larger system.
@@ -498,7 +558,7 @@ The `manifest.uuid` file should contain the SHA3-256 hash of the
`manifest` file. If all of the above hash comparisons are correct, then
you can be confident that your source tree is authentic and unadulterated.
Details on the format for the `manifest` files are available
-[on the Fossil website](https://fossil-scm.org/fossil/doc/trunk/www/fileformat.wiki#manifest).
+[on the Fossil website](https://fossil-scm.org/home/doc/trunk/www/fileformat.wiki#manifest).
The process of checking source code authenticity is automated by the
makefile:
@@ -515,7 +575,11 @@ hidden by also modifying the makefiles.
## Contacts
-The main SQLite website is [http:/sqlite.org/](http://sqlite.org/)
+The main SQLite website is [https://sqlite.org/](https://sqlite.org/)
with geographically distributed backups at
-[http://www2.sqlite.org/](http://www2.sqlite.org) and
-[http://www3.sqlite.org/](http://www3.sqlite.org).
+[https://www2.sqlite.org/](https://www2.sqlite.org) and
+[https://www3.sqlite.org/](https://www3.sqlite.org).
+
+Contact the SQLite developers through the
+[SQLite Forum](https://sqlite.org/forum/). In an emergency, you
+can send private email to the lead developer at drh at sqlite dot org.
diff --git a/SQLCipher.podspec.json b/SQLCipher.podspec.json
index 3157bd1b3b..05c9daf8cb 100644
--- a/SQLCipher.podspec.json
+++ b/SQLCipher.podspec.json
@@ -3,22 +3,25 @@
"default_subspecs": "standard",
"description": "SQLCipher is an open source extension to SQLite that provides transparent 256-bit AES encryption of database files.",
"homepage": "https://www.zetetic.net/sqlcipher/",
- "license": "BSD",
+ "license": {
+ "type": "BSD-3-Clause",
+ "file": "LICENSE.txt"
+ },
"name": "SQLCipher",
"platforms": {
- "ios": "11.0",
+ "ios": "12.0",
"osx": "10.13",
- "tvos": "11.0",
+ "tvos": "12.0",
"watchos": "7.0"
},
- "prepare_command": "./configure --enable-tempstore=yes --with-crypto-lib=commoncrypto CFLAGS=\"-DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999\"; make sqlite3.c",
+ "prepare_command": "./configure && make sqlite3.c",
"requires_arc": false,
"source": {
"git": "https://github.com/sqlcipher/sqlcipher.git",
- "tag": "v4.5.6"
+ "tag": "v4.9.0"
},
"summary": "Full Database Encryption for SQLite.",
- "version": "4.5.6",
+ "version": "4.9.0",
"subspecs": [
{
"compiler_flags": [
@@ -41,7 +44,9 @@
"-DSQLITE_ENABLE_FTS5",
"-DSQLCIPHER_CRYPTO_CC",
"-DHAVE_USLEEP=1",
- "-DSQLITE_MAX_VARIABLE_NUMBER=99999"
+ "-DSQLITE_MAX_VARIABLE_NUMBER=99999",
+ "-DSQLITE_EXTRA_INIT=sqlcipher_extra_init",
+ "-DSQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown"
],
"frameworks": [
"Foundation",
@@ -49,10 +54,14 @@
],
"name": "common",
"source_files": "sqlite3.{h,c}",
+ "resource_bundles": {"SQLCipher": ["sqlcipher-resources/PrivacyInfo.xcprivacy"]},
"xcconfig": {
"HEADER_SEARCH_PATHS": "$(PODS_ROOT)/SQLCipher",
- "GCC_PREPROCESSOR_DEFINITIONS": "$(inherited) SQLITE_HAS_CODEC=1",
- "OTHER_CFLAGS": "$(inherited) -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLCIPHER_CRYPTO_CC -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999"
+ "GCC_PREPROCESSOR_DEFINITIONS": "SQLITE_HAS_CODEC=1",
+ "OTHER_CFLAGS": "$(inherited) -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLITE_SOUNDEX -DSQLITE_THREADSAFE -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_STAT3 -DSQLITE_ENABLE_STAT4 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_MEMORY_MANAGEMENT -DSQLITE_ENABLE_LOAD_EXTENSION -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS4_UNICODE61 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_UNLOCK_NOTIFY -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLCIPHER_CRYPTO_CC -DHAVE_USLEEP=1 -DSQLITE_MAX_VARIABLE_NUMBER=99999 -DSQLITE_EXTRA_INIT=sqlcipher_extra_init -DSQLITE_EXTRA_SHUTDOWN=sqlcipher_extra_shutdown"
+ },
+ "user_target_xcconfig": {
+ "GCC_PREPROCESSOR_DEFINITIONS": "_SQLITE3_H_=1 _FTS5_H=1 _SQLITE3RTREE_H_=1"
}
},
{
diff --git a/VERSION b/VERSION
index 1b9d70c301..46325cfb25 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.44.2
+3.49.2
diff --git a/aclocal.m4 b/aclocal.m4
deleted file mode 100644
index eb9236a233..0000000000
--- a/aclocal.m4
+++ /dev/null
@@ -1,9068 +0,0 @@
-# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
-
-# Copyright (C) 1996-2021 Free Software Foundation, Inc.
-
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
-# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
-#
-# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
-# Written by Gordon Matzigkeit, 1996
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-m4_define([_LT_COPYING], [dnl
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions. There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# GNU Libtool is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
-# (at your option) any later version.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program or library that is built
-# using GNU Libtool, you may include this file under the same
-# distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-])
-
-# serial 58 LT_INIT
-
-
-# LT_PREREQ(VERSION)
-# ------------------
-# Complain and exit if this libtool version is less that VERSION.
-m4_defun([LT_PREREQ],
-[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
- [m4_default([$3],
- [m4_fatal([Libtool version $1 or higher is required],
- 63)])],
- [$2])])
-
-
-# _LT_CHECK_BUILDDIR
-# ------------------
-# Complain if the absolute build directory name contains unusual characters
-m4_defun([_LT_CHECK_BUILDDIR],
-[case `pwd` in
- *\ * | *\ *)
- AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
-esac
-])
-
-
-# LT_INIT([OPTIONS])
-# ------------------
-AC_DEFUN([LT_INIT],
-[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
-AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
-AC_BEFORE([$0], [LT_LANG])dnl
-AC_BEFORE([$0], [LT_OUTPUT])dnl
-AC_BEFORE([$0], [LTDL_INIT])dnl
-m4_require([_LT_CHECK_BUILDDIR])dnl
-
-dnl Autoconf doesn't catch unexpanded LT_ macros by default:
-m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
-m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
-dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
-dnl unless we require an AC_DEFUNed macro:
-AC_REQUIRE([LTOPTIONS_VERSION])dnl
-AC_REQUIRE([LTSUGAR_VERSION])dnl
-AC_REQUIRE([LTVERSION_VERSION])dnl
-AC_REQUIRE([LTOBSOLETE_VERSION])dnl
-m4_require([_LT_PROG_LTMAIN])dnl
-
-_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
-
-dnl Parse OPTIONS
-_LT_SET_OPTIONS([$0], [$1])
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS=$ltmain
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-AC_SUBST(LIBTOOL)dnl
-
-_LT_SETUP
-
-# Only expand once:
-m4_define([LT_INIT])
-])# LT_INIT
-
-# Old names:
-AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
-AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
-dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
-
-
-# _LT_PREPARE_CC_BASENAME
-# -----------------------
-m4_defun([_LT_PREPARE_CC_BASENAME], [
-# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
- for cc_temp in @S|@*""; do
- case $cc_temp in
- compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
- distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
- \-*) ;;
- *) break;;
- esac
- done
- func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-])# _LT_PREPARE_CC_BASENAME
-
-
-# _LT_CC_BASENAME(CC)
-# -------------------
-# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
-# but that macro is also expanded into generated libtool script, which
-# arranges for $SED and $ECHO to be set by different means.
-m4_defun([_LT_CC_BASENAME],
-[m4_require([_LT_PREPARE_CC_BASENAME])dnl
-AC_REQUIRE([_LT_DECL_SED])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-func_cc_basename $1
-cc_basename=$func_cc_basename_result
-])
-
-
-# _LT_FILEUTILS_DEFAULTS
-# ----------------------
-# It is okay to use these file commands and assume they have been set
-# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
-m4_defun([_LT_FILEUTILS_DEFAULTS],
-[: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-])# _LT_FILEUTILS_DEFAULTS
-
-
-# _LT_SETUP
-# ---------
-m4_defun([_LT_SETUP],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
-
-_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
-dnl
-_LT_DECL([], [host_alias], [0], [The host system])dnl
-_LT_DECL([], [host], [0])dnl
-_LT_DECL([], [host_os], [0])dnl
-dnl
-_LT_DECL([], [build_alias], [0], [The build system])dnl
-_LT_DECL([], [build], [0])dnl
-_LT_DECL([], [build_os], [0])dnl
-dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-dnl
-AC_REQUIRE([AC_PROG_LN_S])dnl
-test -z "$LN_S" && LN_S="ln -s"
-_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
-dnl
-AC_REQUIRE([LT_CMD_MAX_LEN])dnl
-_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
-_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
-dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
-m4_require([_LT_CMD_RELOAD])dnl
-m4_require([_LT_CHECK_MAGIC_METHOD])dnl
-m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
-m4_require([_LT_CMD_OLD_ARCHIVE])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_WITH_SYSROOT])dnl
-m4_require([_LT_CMD_TRUNCATE])dnl
-
-_LT_CONFIG_LIBTOOL_INIT([
-# See if we are running on zsh, and set the options that allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-])
-if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-
-_LT_CHECK_OBJDIR
-
-m4_require([_LT_TAG_COMPILER])dnl
-
-case $host_os in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-_LT_CC_BASENAME([$compiler])
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- _LT_PATH_MAGIC
- fi
- ;;
-esac
-
-# Use C for the default configuration in the libtool script
-LT_SUPPORTED_TAG([CC])
-_LT_LANG_C_CONFIG
-_LT_LANG_DEFAULT_CONFIG
-_LT_CONFIG_COMMANDS
-])# _LT_SETUP
-
-
-# _LT_PREPARE_SED_QUOTE_VARS
-# --------------------------
-# Define a few sed substitution that help us do robust quoting.
-m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
-[# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\([["`\\]]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-])
-
-# _LT_PROG_LTMAIN
-# ---------------
-# Note that this code is called both from 'configure', and 'config.status'
-# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
-# 'config.status' has no value for ac_aux_dir unless we are using Automake,
-# so we pass a copy along to make sure it has a sensible value anyway.
-m4_defun([_LT_PROG_LTMAIN],
-[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
-_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
-ltmain=$ac_aux_dir/ltmain.sh
-])# _LT_PROG_LTMAIN
-
-
-
-# So that we can recreate a full libtool script including additional
-# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
-# in macros and then make a single call at the end using the 'libtool'
-# label.
-
-
-# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
-# ----------------------------------------
-# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL_INIT],
-[m4_ifval([$1],
- [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
- [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_INIT])
-
-
-# _LT_CONFIG_LIBTOOL([COMMANDS])
-# ------------------------------
-# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
-m4_define([_LT_CONFIG_LIBTOOL],
-[m4_ifval([$1],
- [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
- [$1
-])])])
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
-
-
-# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
-# -----------------------------------------------------
-m4_defun([_LT_CONFIG_SAVE_COMMANDS],
-[_LT_CONFIG_LIBTOOL([$1])
-_LT_CONFIG_LIBTOOL_INIT([$2])
-])
-
-
-# _LT_FORMAT_COMMENT([COMMENT])
-# -----------------------------
-# Add leading comment marks to the start of each line, and a trailing
-# full-stop to the whole comment if one is not present already.
-m4_define([_LT_FORMAT_COMMENT],
-[m4_ifval([$1], [
-m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
- [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
-)])
-
-
-
-
-
-# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
-# -------------------------------------------------------------------
-# CONFIGNAME is the name given to the value in the libtool script.
-# VARNAME is the (base) name used in the configure script.
-# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
-# VARNAME. Any other value will be used directly.
-m4_define([_LT_DECL],
-[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
- [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
- [m4_ifval([$1], [$1], [$2])])
- lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
- m4_ifval([$4],
- [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
- lt_dict_add_subkey([lt_decl_dict], [$2],
- [tagged?], [m4_ifval([$5], [yes], [no])])])
-])
-
-
-# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
-# --------------------------------------------------------
-m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
-
-
-# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_tag_varnames],
-[_lt_decl_filter([tagged?], [yes], $@)])
-
-
-# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
-# ---------------------------------------------------------
-m4_define([_lt_decl_filter],
-[m4_case([$#],
- [0], [m4_fatal([$0: too few arguments: $#])],
- [1], [m4_fatal([$0: too few arguments: $#: $1])],
- [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
- [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
- [lt_dict_filter([lt_decl_dict], $@)])[]dnl
-])
-
-
-# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
-# --------------------------------------------------
-m4_define([lt_decl_quote_varnames],
-[_lt_decl_filter([value], [1], $@)])
-
-
-# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_dquote_varnames],
-[_lt_decl_filter([value], [2], $@)])
-
-
-# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
-# ---------------------------------------------------
-m4_define([lt_decl_varnames_tagged],
-[m4_assert([$# <= 2])dnl
-_$0(m4_quote(m4_default([$1], [[, ]])),
- m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
- m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
-m4_define([_lt_decl_varnames_tagged],
-[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
-
-
-# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
-# ------------------------------------------------
-m4_define([lt_decl_all_varnames],
-[_$0(m4_quote(m4_default([$1], [[, ]])),
- m4_if([$2], [],
- m4_quote(lt_decl_varnames),
- m4_quote(m4_shift($@))))[]dnl
-])
-m4_define([_lt_decl_all_varnames],
-[lt_join($@, lt_decl_varnames_tagged([$1],
- lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
-])
-
-
-# _LT_CONFIG_STATUS_DECLARE([VARNAME])
-# ------------------------------------
-# Quote a variable value, and forward it to 'config.status' so that its
-# declaration there will have the same value as in 'configure'. VARNAME
-# must have a single quote delimited value for this to work.
-m4_define([_LT_CONFIG_STATUS_DECLARE],
-[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
-
-
-# _LT_CONFIG_STATUS_DECLARATIONS
-# ------------------------------
-# We delimit libtool config variables with single quotes, so when
-# we write them to config.status, we have to be sure to quote all
-# embedded single quotes properly. In configure, this macro expands
-# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
-#
-# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`'
-m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
- [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAGS
-# ----------------
-# Output comment and list of tags supported by the script
-m4_defun([_LT_LIBTOOL_TAGS],
-[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
-available_tags='_LT_TAGS'dnl
-])
-
-
-# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
-# -----------------------------------
-# Extract the dictionary values for VARNAME (optionally with TAG) and
-# expand to a commented shell variable setting:
-#
-# # Some comment about what VAR is for.
-# visible_name=$lt_internal_name
-m4_define([_LT_LIBTOOL_DECLARE],
-[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
- [description])))[]dnl
-m4_pushdef([_libtool_name],
- m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
-m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
- [0], [_libtool_name=[$]$1],
- [1], [_libtool_name=$lt_[]$1],
- [2], [_libtool_name=$lt_[]$1],
- [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
-m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
-])
-
-
-# _LT_LIBTOOL_CONFIG_VARS
-# -----------------------
-# Produce commented declarations of non-tagged libtool config variables
-# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
-# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
-# section) are produced by _LT_LIBTOOL_TAG_VARS.
-m4_defun([_LT_LIBTOOL_CONFIG_VARS],
-[m4_foreach([_lt_var],
- m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
- [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
-
-
-# _LT_LIBTOOL_TAG_VARS(TAG)
-# -------------------------
-m4_define([_LT_LIBTOOL_TAG_VARS],
-[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
- [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
-
-
-# _LT_TAGVAR(VARNAME, [TAGNAME])
-# ------------------------------
-m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
-
-
-# _LT_CONFIG_COMMANDS
-# -------------------
-# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
-# variables for single and double quote escaping we saved from calls
-# to _LT_DECL, we can put quote escaped variables declarations
-# into 'config.status', and then the shell code to quote escape them in
-# for loops in 'config.status'. Finally, any additional code accumulated
-# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
-m4_defun([_LT_CONFIG_COMMANDS],
-[AC_PROVIDE_IFELSE([LT_OUTPUT],
- dnl If the libtool generation code has been placed in $CONFIG_LT,
- dnl instead of duplicating it all over again into config.status,
- dnl then we will have config.status run $CONFIG_LT later, so it
- dnl needs to know what name is stored there:
- [AC_CONFIG_COMMANDS([libtool],
- [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
- dnl If the libtool generation code is destined for config.status,
- dnl expand the accumulated commands and init code now:
- [AC_CONFIG_COMMANDS([libtool],
- [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
-])#_LT_CONFIG_COMMANDS
-
-
-# Initialize.
-m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
-[
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-_LT_CONFIG_STATUS_DECLARATIONS
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-\$[]1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_quote_varnames); do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-# Double-quote double-evaled strings.
-for var in lt_decl_all_varnames([[ \
-]], lt_decl_dquote_varnames); do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[[\\\\\\\`\\"\\\$]]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-_LT_OUTPUT_LIBTOOL_INIT
-])
-
-# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
-# ------------------------------------
-# Generate a child script FILE with all initialization necessary to
-# reuse the environment learned by the parent script, and make the
-# file executable. If COMMENT is supplied, it is inserted after the
-# '#!' sequence but before initialization text begins. After this
-# macro, additional text can be appended to FILE to form the body of
-# the child script. The macro ends with non-zero status if the
-# file could not be fully written (such as if the disk is full).
-m4_ifdef([AS_INIT_GENERATED],
-[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
-[m4_defun([_LT_GENERATED_FILE_INIT],
-[m4_require([AS_PREPARE])]dnl
-[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
-[lt_write_fail=0
-cat >$1 <<_ASEOF || lt_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-$2
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$1 <<\_ASEOF || lt_write_fail=1
-AS_SHELL_SANITIZE
-_AS_PREPARE
-exec AS_MESSAGE_FD>&1
-_ASEOF
-test 0 = "$lt_write_fail" && chmod +x $1[]dnl
-m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
-
-# LT_OUTPUT
-# ---------
-# This macro allows early generation of the libtool script (before
-# AC_OUTPUT is called), incase it is used in configure for compilation
-# tests.
-AC_DEFUN([LT_OUTPUT],
-[: ${CONFIG_LT=./config.lt}
-AC_MSG_NOTICE([creating $CONFIG_LT])
-_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
-[# Run this file to recreate a libtool stub with the current configuration.])
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-lt_cl_silent=false
-exec AS_MESSAGE_LOG_FD>>config.log
-{
- echo
- AS_BOX([Running $as_me.])
-} >&AS_MESSAGE_LOG_FD
-
-lt_cl_help="\
-'$as_me' creates a local libtool stub from the current configuration,
-for use in further configure time tests before the real libtool is
-generated.
-
-Usage: $[0] [[OPTIONS]]
-
- -h, --help print this help, then exit
- -V, --version print version number, then exit
- -q, --quiet do not print progress messages
- -d, --debug don't remove temporary files
-
-Report bugs to ."
-
-lt_cl_version="\
-m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
-m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
-configured by $[0], generated by m4_PACKAGE_STRING.
-
-Copyright (C) 2011 Free Software Foundation, Inc.
-This config.lt script is free software; the Free Software Foundation
-gives unlimited permision to copy, distribute and modify it."
-
-while test 0 != $[#]
-do
- case $[1] in
- --version | --v* | -V )
- echo "$lt_cl_version"; exit 0 ;;
- --help | --h* | -h )
- echo "$lt_cl_help"; exit 0 ;;
- --debug | --d* | -d )
- debug=: ;;
- --quiet | --q* | --silent | --s* | -q )
- lt_cl_silent=: ;;
-
- -*) AC_MSG_ERROR([unrecognized option: $[1]
-Try '$[0] --help' for more information.]) ;;
-
- *) AC_MSG_ERROR([unrecognized argument: $[1]
-Try '$[0] --help' for more information.]) ;;
- esac
- shift
-done
-
-if $lt_cl_silent; then
- exec AS_MESSAGE_FD>/dev/null
-fi
-_LTEOF
-
-cat >>"$CONFIG_LT" <<_LTEOF
-_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
-_LTEOF
-
-cat >>"$CONFIG_LT" <<\_LTEOF
-AC_MSG_NOTICE([creating $ofile])
-_LT_OUTPUT_LIBTOOL_COMMANDS
-AS_EXIT(0)
-_LTEOF
-chmod +x "$CONFIG_LT"
-
-# configure is writing to config.log, but config.lt does its own redirection,
-# appending to config.log, which fails on DOS, as config.log is still kept
-# open by configure. Here we exec the FD to /dev/null, effectively closing
-# config.log, so it can be properly (re)opened and appended to by config.lt.
-lt_cl_success=:
-test yes = "$silent" &&
- lt_config_lt_args="$lt_config_lt_args --quiet"
-exec AS_MESSAGE_LOG_FD>/dev/null
-$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
-exec AS_MESSAGE_LOG_FD>>config.log
-$lt_cl_success || AS_EXIT(1)
-])# LT_OUTPUT
-
-
-# _LT_CONFIG(TAG)
-# ---------------
-# If TAG is the built-in tag, create an initial libtool script with a
-# default configuration from the untagged config vars. Otherwise add code
-# to config.status for appending the configuration named by TAG from the
-# matching tagged config vars.
-m4_defun([_LT_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_CONFIG_SAVE_COMMANDS([
- m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
- m4_if(_LT_TAG, [C], [
- # See if we are running on zsh, and set the options that allow our
- # commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
- fi
-
- cfgfile=${ofile}T
- trap "$RM \"$cfgfile\"; exit 1" 1 2 15
- $RM "$cfgfile"
-
- cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit, 1996
-
-_LT_COPYING
-_LT_LIBTOOL_TAGS
-
-# Configured defaults for sys_lib_dlsearch_path munging.
-: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
-
-# ### BEGIN LIBTOOL CONFIG
-_LT_LIBTOOL_CONFIG_VARS
-_LT_LIBTOOL_TAG_VARS
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
- cat <<'_LT_EOF' >> "$cfgfile"
-
-# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_PREPARE_MUNGE_PATH_LIST
-_LT_PREPARE_CC_BASENAME
-
-# ### END FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_EOF
-
- case $host_os in
- aix3*)
- cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-_LT_EOF
- ;;
- esac
-
- _LT_PROG_LTMAIN
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
- || (rm -f "$cfgfile"; exit 1)
-
- mv -f "$cfgfile" "$ofile" ||
- (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
- chmod +x "$ofile"
-],
-[cat <<_LT_EOF >> "$ofile"
-
-dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
-dnl in a comment (ie after a #).
-# ### BEGIN LIBTOOL TAG CONFIG: $1
-_LT_LIBTOOL_TAG_VARS(_LT_TAG)
-# ### END LIBTOOL TAG CONFIG: $1
-_LT_EOF
-])dnl /m4_if
-],
-[m4_if([$1], [], [
- PACKAGE='$PACKAGE'
- VERSION='$VERSION'
- RM='$RM'
- ofile='$ofile'], [])
-])dnl /_LT_CONFIG_SAVE_COMMANDS
-])# _LT_CONFIG
-
-
-# LT_SUPPORTED_TAG(TAG)
-# ---------------------
-# Trace this macro to discover what tags are supported by the libtool
-# --tag option, using:
-# autoconf --trace 'LT_SUPPORTED_TAG:$1'
-AC_DEFUN([LT_SUPPORTED_TAG], [])
-
-
-# C support is built-in for now
-m4_define([_LT_LANG_C_enabled], [])
-m4_define([_LT_TAGS], [])
-
-
-# LT_LANG(LANG)
-# -------------
-# Enable libtool support for the given language if not already enabled.
-AC_DEFUN([LT_LANG],
-[AC_BEFORE([$0], [LT_OUTPUT])dnl
-m4_case([$1],
- [C], [_LT_LANG(C)],
- [C++], [_LT_LANG(CXX)],
- [Go], [_LT_LANG(GO)],
- [Java], [_LT_LANG(GCJ)],
- [Fortran 77], [_LT_LANG(F77)],
- [Fortran], [_LT_LANG(FC)],
- [Windows Resource], [_LT_LANG(RC)],
- [m4_ifdef([_LT_LANG_]$1[_CONFIG],
- [_LT_LANG($1)],
- [m4_fatal([$0: unsupported language: "$1"])])])dnl
-])# LT_LANG
-
-
-# _LT_LANG(LANGNAME)
-# ------------------
-m4_defun([_LT_LANG],
-[m4_ifdef([_LT_LANG_]$1[_enabled], [],
- [LT_SUPPORTED_TAG([$1])dnl
- m4_append([_LT_TAGS], [$1 ])dnl
- m4_define([_LT_LANG_]$1[_enabled], [])dnl
- _LT_LANG_$1_CONFIG($1)])dnl
-])# _LT_LANG
-
-
-m4_ifndef([AC_PROG_GO], [
-# NOTE: This macro has been submitted for inclusion into #
-# GNU Autoconf as AC_PROG_GO. When it is available in #
-# a released version of Autoconf we should remove this #
-# macro and use it instead. #
-m4_defun([AC_PROG_GO],
-[AC_LANG_PUSH(Go)dnl
-AC_ARG_VAR([GOC], [Go compiler command])dnl
-AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
-_AC_ARG_VAR_LDFLAGS()dnl
-AC_CHECK_TOOL(GOC, gccgo)
-if test -z "$GOC"; then
- if test -n "$ac_tool_prefix"; then
- AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
- fi
-fi
-if test -z "$GOC"; then
- AC_CHECK_PROG(GOC, gccgo, gccgo, false)
-fi
-])#m4_defun
-])#m4_ifndef
-
-
-# _LT_LANG_DEFAULT_CONFIG
-# -----------------------
-m4_defun([_LT_LANG_DEFAULT_CONFIG],
-[AC_PROVIDE_IFELSE([AC_PROG_CXX],
- [LT_LANG(CXX)],
- [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_F77],
- [LT_LANG(F77)],
- [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
-
-AC_PROVIDE_IFELSE([AC_PROG_FC],
- [LT_LANG(FC)],
- [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
-
-dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
-dnl pulling things in needlessly.
-AC_PROVIDE_IFELSE([AC_PROG_GCJ],
- [LT_LANG(GCJ)],
- [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
- [LT_LANG(GCJ)],
- [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
- [LT_LANG(GCJ)],
- [m4_ifdef([AC_PROG_GCJ],
- [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
- m4_ifdef([A][M_PROG_GCJ],
- [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
- m4_ifdef([LT_PROG_GCJ],
- [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
-
-AC_PROVIDE_IFELSE([AC_PROG_GO],
- [LT_LANG(GO)],
- [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
-
-AC_PROVIDE_IFELSE([LT_PROG_RC],
- [LT_LANG(RC)],
- [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
-])# _LT_LANG_DEFAULT_CONFIG
-
-# Obsolete macros:
-AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
-AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
-AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
-AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
-AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
-dnl AC_DEFUN([AC_LIBTOOL_F77], [])
-dnl AC_DEFUN([AC_LIBTOOL_FC], [])
-dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
-dnl AC_DEFUN([AC_LIBTOOL_RC], [])
-
-
-# _LT_TAG_COMPILER
-# ----------------
-m4_defun([_LT_TAG_COMPILER],
-[AC_REQUIRE([AC_PROG_CC])dnl
-
-_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
-_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
-_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
-_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-])# _LT_TAG_COMPILER
-
-
-# _LT_COMPILER_BOILERPLATE
-# ------------------------
-# Check for compiler boilerplate output or warnings with
-# the simple compiler test code.
-m4_defun([_LT_COMPILER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-])# _LT_COMPILER_BOILERPLATE
-
-
-# _LT_LINKER_BOILERPLATE
-# ----------------------
-# Check for linker boilerplate output or warnings with
-# the simple link test code.
-m4_defun([_LT_LINKER_BOILERPLATE],
-[m4_require([_LT_DECL_SED])dnl
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-])# _LT_LINKER_BOILERPLATE
-
-# _LT_REQUIRED_DARWIN_CHECKS
-# -------------------------
-m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
- case $host_os in
- rhapsody* | darwin*)
- AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
- AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
- AC_CHECK_TOOL([LIPO], [lipo], [:])
- AC_CHECK_TOOL([OTOOL], [otool], [:])
- AC_CHECK_TOOL([OTOOL64], [otool64], [:])
- _LT_DECL([], [DSYMUTIL], [1],
- [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
- _LT_DECL([], [NMEDIT], [1],
- [Tool to change global to local symbols on Mac OS X])
- _LT_DECL([], [LIPO], [1],
- [Tool to manipulate fat objects and archives on Mac OS X])
- _LT_DECL([], [OTOOL], [1],
- [ldd/readelf like tool for Mach-O binaries on Mac OS X])
- _LT_DECL([], [OTOOL64], [1],
- [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
-
- AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
- [lt_cv_apple_cc_single_mod=no
- if test -z "$LT_MULTI_MODULE"; then
- # By default we will add the -single_module flag. You can override
- # by either setting the environment variable LT_MULTI_MODULE
- # non-empty at configure time, or by adding -multi_module to the
- # link flags.
- rm -rf libconftest.dylib*
- echo "int foo(void){return 1;}" > conftest.c
- echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
- -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
- _lt_result=$?
- # If there is a non-empty error log, and "single_module"
- # appears in it, assume the flag caused a linker warning
- if test -s conftest.err && $GREP single_module conftest.err; then
- cat conftest.err >&AS_MESSAGE_LOG_FD
- # Otherwise, if the output was created with a 0 exit code from
- # the compiler, it worked.
- elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
- lt_cv_apple_cc_single_mod=yes
- else
- cat conftest.err >&AS_MESSAGE_LOG_FD
- fi
- rm -rf libconftest.dylib*
- rm -f conftest.*
- fi])
-
- AC_CACHE_CHECK([for -exported_symbols_list linker flag],
- [lt_cv_ld_exported_symbols_list],
- [lt_cv_ld_exported_symbols_list=no
- save_LDFLAGS=$LDFLAGS
- echo "_main" > conftest.sym
- LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
- [lt_cv_ld_exported_symbols_list=yes],
- [lt_cv_ld_exported_symbols_list=no])
- LDFLAGS=$save_LDFLAGS
- ])
-
- AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
- [lt_cv_ld_force_load=no
- cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
- echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
- $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
- echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
- $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
- cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
- $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
- _lt_result=$?
- if test -s conftest.err && $GREP force_load conftest.err; then
- cat conftest.err >&AS_MESSAGE_LOG_FD
- elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
- lt_cv_ld_force_load=yes
- else
- cat conftest.err >&AS_MESSAGE_LOG_FD
- fi
- rm -f conftest.err libconftest.a conftest conftest.c
- rm -rf conftest.dSYM
- ])
- case $host_os in
- rhapsody* | darwin1.[[012]])
- _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
- darwin1.*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[[012]][[,.]]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*|11.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- esac
- ;;
- esac
- if test yes = "$lt_cv_apple_cc_single_mod"; then
- _lt_dar_single_mod='$single_module'
- fi
- if test yes = "$lt_cv_ld_exported_symbols_list"; then
- _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
- else
- _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
- fi
- if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
- _lt_dsymutil='~$DSYMUTIL $lib || :'
- else
- _lt_dsymutil=
- fi
- ;;
- esac
-])
-
-
-# _LT_DARWIN_LINKER_FEATURES([TAG])
-# ---------------------------------
-# Checks for linker and compiler features on darwin
-m4_defun([_LT_DARWIN_LINKER_FEATURES],
-[
- m4_require([_LT_REQUIRED_DARWIN_CHECKS])
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_automatic, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- if test yes = "$lt_cv_ld_force_load"; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
- m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
- [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)=''
- fi
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
- case $cc_basename in
- ifort*|nagfor*) _lt_dar_can_shared=yes ;;
- *) _lt_dar_can_shared=$GCC ;;
- esac
- if test yes = "$_lt_dar_can_shared"; then
- output_verbose_link_cmd=func_echo_all
- _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
- _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
- _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
- m4_if([$1], [CXX],
-[ if test yes != "$lt_cv_apple_cc_single_mod"; then
- _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
- fi
-],[])
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
-])
-
-# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
-# ----------------------------------
-# Links a minimal program and checks the executable
-# for the system default hardcoded library path. In most cases,
-# this is /usr/lib:/lib, but when the MPI compilers are used
-# the location of the communication and MPI libs are included too.
-# If we don't find anything, use the default library path according
-# to the aix ld manual.
-# Store the results from the different compilers for each TAGNAME.
-# Allow to override them for all tags through lt_cv_aix_libpath.
-m4_defun([_LT_SYS_MODULE_PATH_AIX],
-[m4_require([_LT_DECL_SED])dnl
-if test set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
- [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
- lt_aix_libpath_sed='[
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }]'
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- fi],[])
- if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
- _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
- fi
- ])
- aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
-fi
-])# _LT_SYS_MODULE_PATH_AIX
-
-
-# _LT_SHELL_INIT(ARG)
-# -------------------
-m4_define([_LT_SHELL_INIT],
-[m4_divert_text([M4SH-INIT], [$1
-])])# _LT_SHELL_INIT
-
-
-
-# _LT_PROG_ECHO_BACKSLASH
-# -----------------------
-# Find how we can fake an echo command that does not interpret backslash.
-# In particular, with Autoconf 2.60 or later we add some code to the start
-# of the generated configure script that will find a shell with a builtin
-# printf (that we can use as an echo command).
-m4_defun([_LT_PROG_ECHO_BACKSLASH],
-[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-AC_MSG_CHECKING([how to print strings])
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
- test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='printf %s\n'
-else
- # Use this function as a fallback that always works.
- func_fallback_echo ()
- {
- eval 'cat <<_LTECHO_EOF
-$[]1
-_LTECHO_EOF'
- }
- ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
- $ECHO "$*"
-}
-
-case $ECHO in
- printf*) AC_MSG_RESULT([printf]) ;;
- print*) AC_MSG_RESULT([print -r]) ;;
- *) AC_MSG_RESULT([cat]) ;;
-esac
-
-m4_ifdef([_AS_DETECT_SUGGESTED],
-[_AS_DETECT_SUGGESTED([
- test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
- ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
- ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
- ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
- PATH=/empty FPATH=/empty; export PATH FPATH
- test "X`printf %s $ECHO`" = "X$ECHO" \
- || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
-
-_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
-_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
-])# _LT_PROG_ECHO_BACKSLASH
-
-
-# _LT_WITH_SYSROOT
-# ----------------
-AC_DEFUN([_LT_WITH_SYSROOT],
-[AC_MSG_CHECKING([for sysroot])
-AC_ARG_WITH([sysroot],
-[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
- [Search for dependent libraries within DIR (or the compiler's sysroot
- if not specified).])],
-[], [with_sysroot=no])
-
-dnl lt_sysroot will always be passed unquoted. We quote it here
-dnl in case the user passed a directory name.
-lt_sysroot=
-case $with_sysroot in #(
- yes)
- if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
- fi
- ;; #(
- /*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
- ;; #(
- no|'')
- ;; #(
- *)
- AC_MSG_RESULT([$with_sysroot])
- AC_MSG_ERROR([The sysroot must be an absolute path.])
- ;;
-esac
-
- AC_MSG_RESULT([${lt_sysroot:-no}])
-_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
-[dependent libraries, and where our libraries should be installed.])])
-
-# _LT_ENABLE_LOCK
-# ---------------
-m4_defun([_LT_ENABLE_LOCK],
-[AC_ARG_ENABLE([libtool-lock],
- [AS_HELP_STRING([--disable-libtool-lock],
- [avoid locking (might break parallel builds)])])
-test no = "$enable_libtool_lock" || enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
- # Find out what ABI is being produced by ac_compile, and set mode
- # options accordingly.
- echo 'int i;' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.$ac_objext` in
- *ELF-32*)
- HPUX_IA64_MODE=32
- ;;
- *ELF-64*)
- HPUX_IA64_MODE=64
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-*-*-irix6*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- if test yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -melf32bsmip"
- ;;
- *N32*)
- LD="${LD-ld} -melf32bmipn32"
- ;;
- *64-bit*)
- LD="${LD-ld} -melf64bmip"
- ;;
- esac
- else
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- fi
- rm -rf conftest*
- ;;
-
-mips64*-*linux*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- emul=elf
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- emul="${emul}32"
- ;;
- *64-bit*)
- emul="${emul}64"
- ;;
- esac
- case `/usr/bin/file conftest.$ac_objext` in
- *MSB*)
- emul="${emul}btsmip"
- ;;
- *LSB*)
- emul="${emul}ltsmip"
- ;;
- esac
- case `/usr/bin/file conftest.$ac_objext` in
- *N32*)
- emul="${emul}n32"
- ;;
- esac
- LD="${LD-ld} -m $emul"
- fi
- rm -rf conftest*
- ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly. Note that the listed cases only cover the
- # situations where additional linker options are needed (such as when
- # doing 32-bit compilation for a host where ld defaults to 64-bit, or
- # vice versa); the common cases where no linker options are needed do
- # not appear in the list.
- echo 'int i;' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.o` in
- *32-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_i386_fbsd"
- ;;
- x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
- *x86-64*)
- LD="${LD-ld} -m elf32_x86_64"
- ;;
- *)
- LD="${LD-ld} -m elf_i386"
- ;;
- esac
- ;;
- powerpc64le-*linux*)
- LD="${LD-ld} -m elf32lppclinux"
- ;;
- powerpc64-*linux*)
- LD="${LD-ld} -m elf32ppclinux"
- ;;
- s390x-*linux*)
- LD="${LD-ld} -m elf_s390"
- ;;
- sparc64-*linux*)
- LD="${LD-ld} -m elf32_sparc"
- ;;
- esac
- ;;
- *64-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_x86_64_fbsd"
- ;;
- x86_64-*linux*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- powerpcle-*linux*)
- LD="${LD-ld} -m elf64lppc"
- ;;
- powerpc-*linux*)
- LD="${LD-ld} -m elf64ppc"
- ;;
- s390*-*linux*|s390*-*tpf*)
- LD="${LD-ld} -m elf64_s390"
- ;;
- sparc*-*linux*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS=$CFLAGS
- CFLAGS="$CFLAGS -belf"
- AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
- [AC_LANG_PUSH(C)
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
- AC_LANG_POP])
- if test yes != "$lt_cv_cc_needs_belf"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS=$SAVE_CFLAGS
- fi
- ;;
-*-*solaris*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo 'int i;' > conftest.$ac_ext
- if AC_TRY_EVAL(ac_compile); then
- case `/usr/bin/file conftest.o` in
- *64-bit*)
- case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris*|x86_64-*-solaris*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
- if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD=${LD-ld}_sol2
- fi
- ;;
- *)
- if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
- LD="${LD-ld} -64"
- fi
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-esac
-
-need_locks=$enable_libtool_lock
-])# _LT_ENABLE_LOCK
-
-
-# _LT_PROG_AR
-# -----------
-m4_defun([_LT_PROG_AR],
-[AC_CHECK_TOOLS(AR, [ar], false)
-: ${AR=ar}
-: ${AR_FLAGS=cr}
-_LT_DECL([], [AR], [1], [The archiver])
-_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
-
-AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
- [lt_cv_ar_at_file=no
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
- [echo conftest.$ac_objext > conftest.lst
- lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
- AC_TRY_EVAL([lt_ar_try])
- if test 0 -eq "$ac_status"; then
- # Ensure the archiver fails upon bogus file names.
- rm -f conftest.$ac_objext libconftest.a
- AC_TRY_EVAL([lt_ar_try])
- if test 0 -ne "$ac_status"; then
- lt_cv_ar_at_file=@
- fi
- fi
- rm -f conftest.* libconftest.a
- ])
- ])
-
-if test no = "$lt_cv_ar_at_file"; then
- archiver_list_spec=
-else
- archiver_list_spec=$lt_cv_ar_at_file
-fi
-_LT_DECL([], [archiver_list_spec], [1],
- [How to feed a file listing to the archiver])
-])# _LT_PROG_AR
-
-
-# _LT_CMD_OLD_ARCHIVE
-# -------------------
-m4_defun([_LT_CMD_OLD_ARCHIVE],
-[_LT_PROG_AR
-
-AC_CHECK_TOOL(STRIP, strip, :)
-test -z "$STRIP" && STRIP=:
-_LT_DECL([], [STRIP], [1], [A symbol stripping program])
-
-AC_CHECK_TOOL(RANLIB, ranlib, :)
-test -z "$RANLIB" && RANLIB=:
-_LT_DECL([], [RANLIB], [1],
- [Commands used to install an old-style archive])
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
- darwin*)
- lock_old_archive_extraction=yes ;;
- *)
- lock_old_archive_extraction=no ;;
-esac
-_LT_DECL([], [old_postinstall_cmds], [2])
-_LT_DECL([], [old_postuninstall_cmds], [2])
-_LT_TAGDECL([], [old_archive_cmds], [2],
- [Commands used to build an old-style archive])
-_LT_DECL([], [lock_old_archive_extraction], [0],
- [Whether to use a lock for old archive extraction])
-])# _LT_CMD_OLD_ARCHIVE
-
-
-# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------------------
-# Check whether the given compiler option works
-AC_DEFUN([_LT_COMPILER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
- [$2=no
- m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&AS_MESSAGE_LOG_FD
- echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- $2=yes
- fi
- fi
- $RM conftest*
-])
-
-if test yes = "[$]$2"; then
- m4_if([$5], , :, [$5])
-else
- m4_if([$6], , :, [$6])
-fi
-])# _LT_COMPILER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
-
-
-# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
-# [ACTION-SUCCESS], [ACTION-FAILURE])
-# ----------------------------------------------------
-# Check whether the given linker option works
-AC_DEFUN([_LT_LINKER_OPTION],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_SED])dnl
-AC_CACHE_CHECK([$1], [$2],
- [$2=no
- save_LDFLAGS=$LDFLAGS
- LDFLAGS="$LDFLAGS $3"
- echo "$lt_simple_link_test_code" > conftest.$ac_ext
- if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&AS_MESSAGE_LOG_FD
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- $2=yes
- fi
- else
- $2=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-])
-
-if test yes = "[$]$2"; then
- m4_if([$4], , :, [$4])
-else
- m4_if([$5], , :, [$5])
-fi
-])# _LT_LINKER_OPTION
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
-
-
-# LT_CMD_MAX_LEN
-#---------------
-AC_DEFUN([LT_CMD_MAX_LEN],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-# find the maximum length of command line arguments
-AC_MSG_CHECKING([the maximum length of command line arguments])
-AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
- i=0
- teststring=ABCD
-
- case $build_os in
- msdosdjgpp*)
- # On DJGPP, this test can blow up pretty badly due to problems in libc
- # (any single argument exceeding 2000 bytes causes a buffer overrun
- # during glob expansion). Even if it were fixed, the result of this
- # check would be larger than it should be.
- lt_cv_sys_max_cmd_len=12288; # 12K is about right
- ;;
-
- gnu*)
- # Under GNU Hurd, this test is not required because there is
- # no limit to the length of command line arguments.
- # Libtool will interpret -1 as no limit whatsoever
- lt_cv_sys_max_cmd_len=-1;
- ;;
-
- cygwin* | mingw* | cegcc*)
- # On Win9x/ME, this test blows up -- it succeeds, but takes
- # about 5 minutes as the teststring grows exponentially.
- # Worse, since 9x/ME are not pre-emptively multitasking,
- # you end up with a "frozen" computer, even though with patience
- # the test eventually succeeds (with a max line length of 256k).
- # Instead, let's just punt: use the minimum linelength reported by
- # all of the supported platforms: 8192 (on NT/2K/XP).
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- mint*)
- # On MiNT this can take a long time and run out of memory.
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- amigaos*)
- # On AmigaOS with pdksh, this test takes hours, literally.
- # So we just punt and use a minimum line length of 8192.
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
- # This has been around since 386BSD, at least. Likely further.
- if test -x /sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
- elif test -x /usr/sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
- else
- lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
- fi
- # And add a safety zone
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
- ;;
-
- interix*)
- # We know the value 262144 and hardcode it with a safety zone (like BSD)
- lt_cv_sys_max_cmd_len=196608
- ;;
-
- os2*)
- # The test takes a long time on OS/2.
- lt_cv_sys_max_cmd_len=8192
- ;;
-
- osf*)
- # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
- # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
- # nice to cause kernel panics so lets avoid the loop below.
- # First set a reasonable default.
- lt_cv_sys_max_cmd_len=16384
- #
- if test -x /sbin/sysconfig; then
- case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
- *1*) lt_cv_sys_max_cmd_len=-1 ;;
- esac
- fi
- ;;
- sco3.2v5*)
- lt_cv_sys_max_cmd_len=102400
- ;;
- sysv5* | sco5v6* | sysv4.2uw2*)
- kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
- if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
- else
- lt_cv_sys_max_cmd_len=32768
- fi
- ;;
- *)
- lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
- if test -n "$lt_cv_sys_max_cmd_len" && \
- test undefined != "$lt_cv_sys_max_cmd_len"; then
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
- else
- # Make teststring a little bigger before we do anything with it.
- # a 1K string should be a reasonable start.
- for i in 1 2 3 4 5 6 7 8; do
- teststring=$teststring$teststring
- done
- SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
- # If test is not a shell built-in, we'll probably end up computing a
- # maximum length that is only half of the actual maximum length, but
- # we can't tell.
- while { test X`env echo "$teststring$teststring" 2>/dev/null` \
- = "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test 17 != "$i" # 1/2 MB should be enough
- do
- i=`expr $i + 1`
- teststring=$teststring$teststring
- done
- # Only check the string length outside the loop.
- lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
- teststring=
- # Add a significant safety factor because C++ compilers can tack on
- # massive amounts of additional arguments before passing them to the
- # linker. It appears as though 1/2 is a usable value.
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
- fi
- ;;
- esac
-])
-if test -n "$lt_cv_sys_max_cmd_len"; then
- AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
-else
- AC_MSG_RESULT(none)
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-_LT_DECL([], [max_cmd_len], [0],
- [What is the maximum length of a command?])
-])# LT_CMD_MAX_LEN
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
-
-
-# _LT_HEADER_DLFCN
-# ----------------
-m4_defun([_LT_HEADER_DLFCN],
-[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
-])# _LT_HEADER_DLFCN
-
-
-# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
-# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
-# ----------------------------------------------------------------
-m4_defun([_LT_TRY_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes = "$cross_compiling"; then :
- [$4]
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-[#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include
-#endif
-
-#include
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
- correspondingly for the symbols needed. */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}]
-_LT_EOF
- if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
- (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) $1 ;;
- x$lt_dlneed_uscore) $2 ;;
- x$lt_dlunknown|x*) $3 ;;
- esac
- else :
- # compilation failed
- $3
- fi
-fi
-rm -fr conftest*
-])# _LT_TRY_DLOPEN_SELF
-
-
-# LT_SYS_DLOPEN_SELF
-# ------------------
-AC_DEFUN([LT_SYS_DLOPEN_SELF],
-[m4_require([_LT_HEADER_DLFCN])dnl
-if test yes != "$enable_dlopen"; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen=load_add_on
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- mingw* | pw32* | cegcc*)
- lt_cv_dlopen=LoadLibrary
- lt_cv_dlopen_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # if libdl is installed we need to link against it
- AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
- lt_cv_dlopen=dyld
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ])
- ;;
-
- tpf*)
- # Don't try to run any link tests for TPF. We know it's impossible
- # because TPF is a cross-compiler, and we know how we open DSOs.
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=no
- ;;
-
- *)
- AC_CHECK_FUNC([shl_load],
- [lt_cv_dlopen=shl_load],
- [AC_CHECK_LIB([dld], [shl_load],
- [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
- [AC_CHECK_FUNC([dlopen],
- [lt_cv_dlopen=dlopen],
- [AC_CHECK_LIB([dl], [dlopen],
- [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
- [AC_CHECK_LIB([svld], [dlopen],
- [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
- [AC_CHECK_LIB([dld], [dld_link],
- [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
- ])
- ])
- ])
- ])
- ])
- ;;
- esac
-
- if test no = "$lt_cv_dlopen"; then
- enable_dlopen=no
- else
- enable_dlopen=yes
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS=$CPPFLAGS
- test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS=$LDFLAGS
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS=$LIBS
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- AC_CACHE_CHECK([whether a program can dlopen itself],
- lt_cv_dlopen_self, [dnl
- _LT_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
- lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
- ])
-
- if test yes = "$lt_cv_dlopen_self"; then
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
- AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
- lt_cv_dlopen_self_static, [dnl
- _LT_TRY_DLOPEN_SELF(
- lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
- lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
- ])
- fi
-
- CPPFLAGS=$save_CPPFLAGS
- LDFLAGS=$save_LDFLAGS
- LIBS=$save_LIBS
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-_LT_DECL([dlopen_support], [enable_dlopen], [0],
- [Whether dlopen is supported])
-_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
- [Whether dlopen of programs is supported])
-_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
- [Whether dlopen of statically linked programs is supported])
-])# LT_SYS_DLOPEN_SELF
-
-# Old name:
-AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
-
-
-# _LT_COMPILER_C_O([TAGNAME])
-# ---------------------------
-# Check to see if options -c and -o are simultaneously supported by compiler.
-# This macro does not hard code the compiler like AC_PROG_CC_C_O.
-m4_defun([_LT_COMPILER_C_O],
-[m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
- [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
- [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&AS_MESSAGE_LOG_FD
- echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
- fi
- fi
- chmod u+w . 2>&AS_MESSAGE_LOG_FD
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-])
-_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
- [Does compiler simultaneously support -c and -o options?])
-])# _LT_COMPILER_C_O
-
-
-# _LT_COMPILER_FILE_LOCKS([TAGNAME])
-# ----------------------------------
-# Check to see if we can do hard links to lock some files if needed
-m4_defun([_LT_COMPILER_FILE_LOCKS],
-[m4_require([_LT_ENABLE_LOCK])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-_LT_COMPILER_C_O([$1])
-
-hard_links=nottested
-if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
- # do not overwrite the value of need_locks provided by the user
- AC_MSG_CHECKING([if we can lock with hard links])
- hard_links=yes
- $RM conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- AC_MSG_RESULT([$hard_links])
- if test no = "$hard_links"; then
- AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
-])# _LT_COMPILER_FILE_LOCKS
-
-
-# _LT_CHECK_OBJDIR
-# ----------------
-m4_defun([_LT_CHECK_OBJDIR],
-[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
-[rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- lt_cv_objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null])
-objdir=$lt_cv_objdir
-_LT_DECL([], [objdir], [0],
- [The name of the directory that contains temporary libtool files])dnl
-m4_pattern_allow([LT_OBJDIR])dnl
-AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
- [Define to the sub-directory where libtool stores uninstalled libraries.])
-])# _LT_CHECK_OBJDIR
-
-
-# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
-# --------------------------------------
-# Check hardcoding attributes.
-m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
-[AC_MSG_CHECKING([how to hardcode library paths into programs])
-_LT_TAGVAR(hardcode_action, $1)=
-if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
- test -n "$_LT_TAGVAR(runpath_var, $1)" ||
- test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
-
- # We can hardcode non-existent directories.
- if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
- test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
- # Linking always hardcodes the temporary library directory.
- _LT_TAGVAR(hardcode_action, $1)=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- _LT_TAGVAR(hardcode_action, $1)=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- _LT_TAGVAR(hardcode_action, $1)=unsupported
-fi
-AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
-
-if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
- test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test yes = "$shlibpath_overrides_runpath" ||
- test no = "$enable_shared"; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-_LT_TAGDECL([], [hardcode_action], [0],
- [How to hardcode a shared library path into an executable])
-])# _LT_LINKER_HARDCODE_LIBPATH
-
-
-# _LT_CMD_STRIPLIB
-# ----------------
-m4_defun([_LT_CMD_STRIPLIB],
-[m4_require([_LT_DECL_EGREP])
-striplib=
-old_striplib=
-AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- AC_MSG_RESULT([yes])
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
- striplib="$STRIP -x"
- old_striplib="$STRIP -S"
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- fi
- ;;
- *)
- AC_MSG_RESULT([no])
- ;;
- esac
-fi
-_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
-_LT_DECL([], [striplib], [1])
-])# _LT_CMD_STRIPLIB
-
-
-# _LT_PREPARE_MUNGE_PATH_LIST
-# ---------------------------
-# Make sure func_munge_path_list() is defined correctly.
-m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
-[[# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-# string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-# string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-# "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-# VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
- case x@S|@2 in
- x)
- ;;
- *:)
- eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
- ;;
- x:*)
- eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
- ;;
- *::*)
- eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
- eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
- ;;
- *)
- eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
- ;;
- esac
-}
-]])# _LT_PREPARE_PATH_LIST
-
-
-# _LT_SYS_DYNAMIC_LINKER([TAG])
-# -----------------------------
-# PORTME Fill in your ld.so characteristics
-m4_defun([_LT_SYS_DYNAMIC_LINKER],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_OBJDUMP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CHECK_SHELL_FEATURES])dnl
-m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
-AC_MSG_CHECKING([dynamic linker characteristics])
-m4_if([$1],
- [], [
-if test yes = "$GCC"; then
- case $host_os in
- darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
- *) lt_awk_arg='/^libraries:/' ;;
- esac
- case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
- *) lt_sed_strip_eq='s|=/|/|g' ;;
- esac
- lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
- case $lt_search_path_spec in
- *\;*)
- # if the path contains ";" then we assume it to be the separator
- # otherwise default to the standard path separator (i.e. ":") - it is
- # assumed that no part of a normal pathname contains ";" but that should
- # okay in the real world where ";" in dirpaths is itself problematic.
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
- ;;
- *)
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
- ;;
- esac
- # Ok, now we have the path, separated by spaces, we can step through it
- # and add multilib dir if necessary...
- lt_tmp_lt_search_path_spec=
- lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
- # ...but if some path component already ends with the multilib dir we assume
- # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
- case "$lt_multi_os_dir; $lt_search_path_spec " in
- "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
- lt_multi_os_dir=
- ;;
- esac
- for lt_sys_path in $lt_search_path_spec; do
- if test -d "$lt_sys_path$lt_multi_os_dir"; then
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
- elif test -n "$lt_multi_os_dir"; then
- test -d "$lt_sys_path" && \
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
- fi
- done
- lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS = " "; FS = "/|\n";} {
- lt_foo = "";
- lt_count = 0;
- for (lt_i = NF; lt_i > 0; lt_i--) {
- if ($lt_i != "" && $lt_i != ".") {
- if ($lt_i == "..") {
- lt_count++;
- } else {
- if (lt_count == 0) {
- lt_foo = "/" $lt_i lt_foo;
- } else {
- lt_count--;
- }
- }
- }
- }
- if (lt_foo != "") { lt_freq[[lt_foo]]++; }
- if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
-}'`
- # AWK program above erroneously prepends '/' to C:/dos/paths
- # for these hosts.
- case $host_os in
- mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
- $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
- esac
- sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi])
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
-[User-defined run-time library search path.])
-
-case $host_os in
-aix3*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='$libname$release$shared_ext$major'
- ;;
-
-aix[[4-9]]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- hardcode_into_libs=yes
- if test ia64 = "$host_cpu"; then
- # AIX 5 supports IA64
- library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- else
- # With GCC up to 2.95.x, collect2 would create an import file
- # for dependence libraries. The import file would start with
- # the line '#! .'. This would cause the generated library to
- # depend on '.', always an invalid library. This was fixed in
- # development snapshots of GCC prior to 3.0.
- case $host_os in
- aix4 | aix4.[[01]] | aix4.[[01]].*)
- if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
- echo ' yes '
- echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # Using Import Files as archive members, it is possible to support
- # filename-based versioning of shared library archives on AIX. While
- # this would work for both with and without runtime linking, it will
- # prevent static linking of such archives. So we do filename-based
- # shared library versioning with .so extension only, which is used
- # when both runtime linking and shared linking is enabled.
- # Unfortunately, runtime linking may impact performance, so we do
- # not want this to be the default eventually. Also, we use the
- # versioned .so libs for executables only if there is the -brtl
- # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
- # To allow for filename-based versioning support, we need to create
- # libNAME.so.V as an archive file, containing:
- # *) an Import File, referring to the versioned filename of the
- # archive as well as the shared archive member, telling the
- # bitwidth (32 or 64) of that shared object, and providing the
- # list of exported symbols of that shared object, eventually
- # decorated with the 'weak' keyword
- # *) the shared object with the F_LOADONLY flag set, to really avoid
- # it being seen by the linker.
- # At run time we better use the real file rather than another symlink,
- # but for link time we create the symlink libNAME.so -> libNAME.so.V
-
- case $with_aix_soname,$aix_use_runtimelinking in
- # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
- # soname into executable. Probably we can add versioning support to
- # collect2, so additional links can be useful in future.
- aix,yes) # traditional libtool
- dynamic_linker='AIX unversionable lib.so'
- # If using run time linking (on AIX 4.2 or later) use lib.so
- # instead of lib.a to let people know that these are not
- # typical AIX shared libraries.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- ;;
- aix,no) # traditional AIX only
- dynamic_linker='AIX lib.a[(]lib.so.V[)]'
- # We preserve .a as extension for shared libraries through AIX4.2
- # and later when we are not doing run time linking.
- library_names_spec='$libname$release.a $libname.a'
- soname_spec='$libname$release$shared_ext$major'
- ;;
- svr4,*) # full svr4 only
- dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
- library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
- # We do not specify a path in Import Files, so LIBPATH fires.
- shlibpath_overrides_runpath=yes
- ;;
- *,yes) # both, prefer svr4
- dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
- library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
- # unpreferred sharedlib libNAME.a needs extra handling
- postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
- postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
- # We do not specify a path in Import Files, so LIBPATH fires.
- shlibpath_overrides_runpath=yes
- ;;
- *,no) # both, prefer aix
- dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
- library_names_spec='$libname$release.a $libname.a'
- soname_spec='$libname$release$shared_ext$major'
- # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
- postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
- postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
- ;;
- esac
- shlibpath_var=LIBPATH
- fi
- ;;
-
-amigaos*)
- case $host_cpu in
- powerpc)
- # Since July 2007 AmigaOS4 officially supports .so libraries.
- # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- ;;
- m68k)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
- ;;
- esac
- ;;
-
-beos*)
- library_names_spec='$libname$shared_ext'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-bsdi[[45]]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
-
- case $GCC,$cc_basename in
- yes,*)
- # gcc
- library_names_spec='$libname.dll.a'
- # DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname~
- chmod a+x \$dldir/$dlname~
- if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
- eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
- fi'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
-
- case $host_os in
- cygwin*)
- # Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-m4_if([$1], [],[
- sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
- ;;
- mingw* | cegcc*)
- # MinGW DLLs use traditional 'lib' prefix
- soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
- ;;
- pw32*)
- # pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- ;;
-
- *,cl*)
- # Native MSVC
- libname_spec='$name'
- soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
- library_names_spec='$libname.dll.lib'
-
- case $build_os in
- mingw*)
- sys_lib_search_path_spec=
- lt_save_ifs=$IFS
- IFS=';'
- for lt_path in $LIB
- do
- IFS=$lt_save_ifs
- # Let DOS variable expansion print the short 8.3 style file name.
- lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
- sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
- done
- IFS=$lt_save_ifs
- # Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
- ;;
- cygwin*)
- # Convert to unix form, then to dos form, then back to unix form
- # but this time dos style (no spaces!) so that the unix form looks
- # like /cygdrive/c/PROGRA~1:/cygdr...
- sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
- sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
- sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- ;;
- *)
- sys_lib_search_path_spec=$LIB
- if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
- # It is most probably a Windows format PATH.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
- else
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- fi
- # FIXME: find the short name or the path components, as spaces are
- # common. (e.g. "Program Files" -> "PROGRA~1")
- ;;
- esac
-
- # DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
- dynamic_linker='Win32 link.exe'
- ;;
-
- *)
- # Assume MSVC wrapper
- library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
- dynamic_linker='Win32 ld.exe'
- ;;
- esac
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- version_type=darwin
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
- soname_spec='$libname$release$major$shared_ext'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-m4_if([$1], [],[
- sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
- sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
- ;;
-
-dgux*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-freebsd* | dragonfly*)
- # DragonFly does not have aout. When/if they implement a new
- # versioning mechanism, adjust this.
- if test -x /usr/bin/objformat; then
- objformat=`/usr/bin/objformat`
- else
- case $host_os in
- freebsd[[23]].*) objformat=aout ;;
- *) objformat=elf ;;
- esac
- fi
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2.*)
- shlibpath_overrides_runpath=yes
- ;;
- freebsd3.[[01]]* | freebsdelf3.[[01]]*)
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
- freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- *) # from 4.6 on, and DragonFly
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-haiku*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- dynamic_linker="$host_os runtime_loader"
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=no
- sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- case $host_cpu in
- ia64*)
- shrext_cmds='.so'
- hardcode_into_libs=yes
- dynamic_linker="$host_os dld.so"
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- if test 32 = "$HPUX_IA64_MODE"; then
- sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
- sys_lib_dlsearch_path_spec=/usr/lib/hpux32
- else
- sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
- sys_lib_dlsearch_path_spec=/usr/lib/hpux64
- fi
- ;;
- hppa*64*)
- shrext_cmds='.sl'
- hardcode_into_libs=yes
- dynamic_linker="$host_os dld.sl"
- shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
- shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
- *)
- shrext_cmds='.sl'
- dynamic_linker="$host_os dld.sl"
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- ;;
- esac
- # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
- postinstall_cmds='chmod 555 $lib'
- # or fails outright, so override atomically:
- install_override_mode=555
- ;;
-
-interix[[3-9]]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $host_os in
- nonstopux*) version_type=nonstopux ;;
- *)
- if test yes = "$lt_cv_prog_gnu_ld"; then
- version_type=linux # correct to gnu/linux during the next big refactor
- else
- version_type=irix
- fi ;;
- esac
- need_lib_prefix=no
- need_version=no
- soname_spec='$libname$release$shared_ext$major'
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
- case $host_os in
- irix5* | nonstopux*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
- libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
- libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
- libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
- sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
- hardcode_into_libs=yes
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
- dynamic_linker=no
- ;;
-
-linux*android*)
- version_type=none # Android doesn't support versioned libraries.
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext'
- soname_spec='$libname$release$shared_ext'
- finish_cmds=
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
-
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- dynamic_linker='Android linker'
- # Don't embed -rpath directories since the linker doesn't support them.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
-
- # Some binutils ld are patched to set DT_RUNPATH
- AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
- [lt_cv_shlibpath_overrides_runpath=no
- save_LDFLAGS=$LDFLAGS
- save_libdir=$libdir
- eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
- LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
- AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
- [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
- [lt_cv_shlibpath_overrides_runpath=yes])])
- LDFLAGS=$save_LDFLAGS
- libdir=$save_libdir
- ])
- shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- # Ideally, we could use ldconfig to report *all* directores which are
- # searched for libraries, however this is still not possible. Aside from not
- # being certain /sbin/ldconfig is available, command
- # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
- # even though it is searched at run-time. Try to do the best guess by
- # appending ld.so.conf contents (and includes) to the search path.
- if test -f /etc/ld.so.conf; then
- lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
- fi
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- dynamic_linker='GNU/Linux ld.so'
- ;;
-
-netbsdelf*-gnu)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='NetBSD ld.elf_so'
- ;;
-
-netbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-newsos6)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-*nto* | *qnx*)
- version_type=qnx
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='ldqnx.so'
- ;;
-
-openbsd* | bitrig*)
- version_type=sunos
- sys_lib_dlsearch_path_spec=/usr/lib
- need_lib_prefix=no
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- need_version=no
- else
- need_version=yes
- fi
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-os2*)
- libname_spec='$name'
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
- # OS/2 can only load a DLL with a base name of 8 characters or less.
- soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
- v=$($ECHO $release$versuffix | tr -d .-);
- n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
- $ECHO $n$v`$shared_ext'
- library_names_spec='${libname}_dll.$libext'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=BEGINLIBPATH
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname~
- chmod a+x \$dldir/$dlname~
- if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
- eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
- fi'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- ;;
-
-osf3* | osf4* | osf5*)
- version_type=osf
- need_lib_prefix=no
- need_version=no
- soname_spec='$libname$release$shared_ext$major'
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
-
-rdos*)
- dynamic_linker=no
- ;;
-
-solaris*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test yes = "$with_gnu_ld"; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.3*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- need_lib_prefix=no
- runpath_var=LD_RUN_PATH
- ;;
- siemens)
- need_lib_prefix=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec; then
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
- soname_spec='$libname$shared_ext.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=sco
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- if test yes = "$with_gnu_ld"; then
- sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
- else
- sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
- case $host_os in
- sco3.2v5*)
- sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
- ;;
- esac
- fi
- sys_lib_dlsearch_path_spec='/usr/lib'
- ;;
-
-tpf*)
- # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-uts4*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-AC_MSG_RESULT([$dynamic_linker])
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
- sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
-fi
-
-if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
- sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
-fi
-
-# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
-configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
-
-# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
-func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
-
-# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
-configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
-
-_LT_DECL([], [variables_saved_for_relink], [1],
- [Variables whose values should be saved in libtool wrapper scripts and
- restored at link time])
-_LT_DECL([], [need_lib_prefix], [0],
- [Do we need the "lib" prefix for modules?])
-_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
-_LT_DECL([], [version_type], [0], [Library versioning type])
-_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
-_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
-_LT_DECL([], [shlibpath_overrides_runpath], [0],
- [Is shlibpath searched before the hard-coded library search path?])
-_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
-_LT_DECL([], [library_names_spec], [1],
- [[List of archive names. First name is the real one, the rest are links.
- The last name is the one that the linker finds with -lNAME]])
-_LT_DECL([], [soname_spec], [1],
- [[The coded name of the library, if different from the real name]])
-_LT_DECL([], [install_override_mode], [1],
- [Permission mode override for installation of shared libraries])
-_LT_DECL([], [postinstall_cmds], [2],
- [Command to use after installation of a shared archive])
-_LT_DECL([], [postuninstall_cmds], [2],
- [Command to use after uninstallation of a shared archive])
-_LT_DECL([], [finish_cmds], [2],
- [Commands used to finish a libtool library installation in a directory])
-_LT_DECL([], [finish_eval], [1],
- [[As "finish_cmds", except a single script fragment to be evaled but
- not shown]])
-_LT_DECL([], [hardcode_into_libs], [0],
- [Whether we should hardcode library paths into libraries])
-_LT_DECL([], [sys_lib_search_path_spec], [2],
- [Compile-time system search path for libraries])
-_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
- [Detected run-time system search path for libraries])
-_LT_DECL([], [configure_time_lt_sys_library_path], [2],
- [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
-])# _LT_SYS_DYNAMIC_LINKER
-
-
-# _LT_PATH_TOOL_PREFIX(TOOL)
-# --------------------------
-# find a file program that can recognize shared library
-AC_DEFUN([_LT_PATH_TOOL_PREFIX],
-[m4_require([_LT_DECL_EGREP])dnl
-AC_MSG_CHECKING([for $1])
-AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
-[case $MAGIC_CMD in
-[[\\/*] | ?:[\\/]*])
- lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
- ;;
-*)
- lt_save_MAGIC_CMD=$MAGIC_CMD
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
-dnl $ac_dummy forces splitting on constant user-supplied paths.
-dnl POSIX.2 word splitting is done only on the output of word expansions,
-dnl not every word. This closes a longstanding sh security hole.
- ac_dummy="m4_if([$2], , $PATH, [$2])"
- for ac_dir in $ac_dummy; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$1"; then
- lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD=$lt_cv_path_MAGIC_CMD
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac])
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- AC_MSG_RESULT($MAGIC_CMD)
-else
- AC_MSG_RESULT(no)
-fi
-_LT_DECL([], [MAGIC_CMD], [0],
- [Used to examine libraries when file_magic_cmd begins with "file"])dnl
-])# _LT_PATH_TOOL_PREFIX
-
-# Old name:
-AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
-
-
-# _LT_PATH_MAGIC
-# --------------
-# find a file program that can recognize a shared library
-m4_defun([_LT_PATH_MAGIC],
-[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
- else
- MAGIC_CMD=:
- fi
-fi
-])# _LT_PATH_MAGIC
-
-
-# LT_PATH_LD
-# ----------
-# find the pathname to the GNU or non-GNU linker
-AC_DEFUN([LT_PATH_LD],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
-
-AC_ARG_WITH([gnu-ld],
- [AS_HELP_STRING([--with-gnu-ld],
- [assume the C compiler uses GNU ld @<:@default=no@:>@])],
- [test no = "$withval" || with_gnu_ld=yes],
- [with_gnu_ld=no])dnl
-
-ac_prog=ld
-if test yes = "$GCC"; then
- # Check if gcc -print-prog-name=ld gives a path.
- AC_MSG_CHECKING([for ld used by $CC])
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return, which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [[\\/]]* | ?:[[\\/]]*)
- re_direlt='/[[^/]][[^/]]*/\.\./'
- # Canonicalize the pathname of ld
- ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
- while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD=$ac_prog
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test yes = "$with_gnu_ld"; then
- AC_MSG_CHECKING([for GNU ld])
-else
- AC_MSG_CHECKING([for non-GNU ld])
-fi
-AC_CACHE_VAL(lt_cv_path_LD,
-[if test -z "$LD"; then
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD=$ac_dir/$ac_prog
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some variants of GNU ld only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- case `"$lt_cv_path_LD" -v 2>&1 &1 conftest.i
-cat conftest.i conftest.i >conftest2.i
-: ${lt_DD:=$DD}
-AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
-[if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then
- cmp -s conftest.i conftest.out \
- && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
-fi])
-rm -f conftest.i conftest2.i conftest.out])
-])# _LT_PATH_DD
-
-
-# _LT_CMD_TRUNCATE
-# ----------------
-# find command to truncate a binary pipe
-m4_defun([_LT_CMD_TRUNCATE],
-[m4_require([_LT_PATH_DD])
-AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
-[printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-lt_cv_truncate_bin=
-if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then
- cmp -s conftest.i conftest.out \
- && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
-fi
-rm -f conftest.i conftest2.i conftest.out
-test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
-_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
- [Command to truncate a binary pipe])
-])# _LT_CMD_TRUNCATE
-
-
-# _LT_CHECK_MAGIC_METHOD
-# ----------------------
-# how to check for library dependencies
-# -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_MAGIC_METHOD],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-AC_CACHE_CHECK([how to recognize dependent libraries],
-lt_cv_deplibs_check_method,
-[lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# 'unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# that responds to the $file_magic_cmd with a given extended regex.
-# If you have 'file' or equivalent on your system and you're not sure
-# whether 'pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[[4-9]]*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi[[45]]*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin*)
- # func_win32_libid is a shell function defined in ltmain.sh
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- ;;
-
-mingw* | pw32*)
- # Base MSYS/MinGW do not provide the 'file' command needed by
- # func_win32_libid shell function, so use a weaker test based on 'objdump',
- # unless we find 'file', for example because we are cross-compiling.
- if ( file / ) >/dev/null 2>&1; then
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- else
- # Keep this pattern in sync with the one in func_win32_libid.
- lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- fi
- ;;
-
-cegcc*)
- # use the weaker test based on 'objdump'. See mingw*.
- lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-freebsd* | dragonfly*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-haiku*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
- case $host_cpu in
- ia64*)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
- lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
- ;;
- hppa*64*)
- [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
- lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
- ;;
- *)
- lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
- esac
- ;;
-
-interix[[3-9]]*)
- # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-*nto* | *qnx*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-openbsd* | bitrig*)
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-rdos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.3*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- siemens)
- lt_cv_deplibs_check_method=pass_all
- ;;
- pc)
- lt_cv_deplibs_check_method=pass_all
- ;;
- esac
- ;;
-
-tpf*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-os2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-esac
-])
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
- case $host_os in
- mingw* | pw32*)
- if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
- want_nocaseglob=yes
- else
- file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
- fi
- ;;
- esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-_LT_DECL([], [deplibs_check_method], [1],
- [Method to check whether dependent libraries are shared objects])
-_LT_DECL([], [file_magic_cmd], [1],
- [Command to use when deplibs_check_method = "file_magic"])
-_LT_DECL([], [file_magic_glob], [1],
- [How to find potential files when deplibs_check_method = "file_magic"])
-_LT_DECL([], [want_nocaseglob], [1],
- [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
-])# _LT_CHECK_MAGIC_METHOD
-
-
-# LT_PATH_NM
-# ----------
-# find the pathname to a BSD- or MS-compatible name lister
-AC_DEFUN([LT_PATH_NM],
-[AC_REQUIRE([AC_PROG_CC])dnl
-AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
-[if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM=$NM
-else
- lt_nm_to_check=${ac_tool_prefix}nm
- if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
- lt_nm_to_check="$lt_nm_to_check nm"
- fi
- for lt_tmp_nm in $lt_nm_to_check; do
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/$lt_tmp_nm
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
- case $build_os in
- mingw*) lt_bad_file=conftest.nm/nofile ;;
- *) lt_bad_file=/dev/null ;;
- esac
- case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
- *$lt_bad_file* | *'Invalid file or object type'*)
- lt_cv_path_NM="$tmp_nm -B"
- break 2
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
- break 2
- ;;
- *)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- ;;
- esac
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
- done
- : ${lt_cv_path_NM=no}
-fi])
-if test no != "$lt_cv_path_NM"; then
- NM=$lt_cv_path_NM
-else
- # Didn't find any BSD compatible name lister, look for dumpbin.
- if test -n "$DUMPBIN"; then :
- # Let the user override the test.
- else
- AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
- case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
- *COFF*)
- DUMPBIN="$DUMPBIN -symbols -headers"
- ;;
- *)
- DUMPBIN=:
- ;;
- esac
- fi
- AC_SUBST([DUMPBIN])
- if test : != "$DUMPBIN"; then
- NM=$DUMPBIN
- fi
-fi
-test -z "$NM" && NM=nm
-AC_SUBST([NM])
-_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
-
-AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
- [lt_cv_nm_interface="BSD nm"
- echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
- (eval "$ac_compile" 2>conftest.err)
- cat conftest.err >&AS_MESSAGE_LOG_FD
- (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
- (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
- cat conftest.err >&AS_MESSAGE_LOG_FD
- (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
- cat conftest.out >&AS_MESSAGE_LOG_FD
- if $GREP 'External.*some_variable' conftest.out > /dev/null; then
- lt_cv_nm_interface="MS dumpbin"
- fi
- rm -f conftest*])
-])# LT_PATH_NM
-
-# Old names:
-AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
-AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_PROG_NM], [])
-dnl AC_DEFUN([AC_PROG_NM], [])
-
-# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-# --------------------------------
-# how to determine the name of the shared library
-# associated with a specific link library.
-# -- PORTME fill in with the dynamic library characteristics
-m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
-[m4_require([_LT_DECL_EGREP])
-m4_require([_LT_DECL_OBJDUMP])
-m4_require([_LT_DECL_DLLTOOL])
-AC_CACHE_CHECK([how to associate runtime and link libraries],
-lt_cv_sharedlib_from_linklib_cmd,
-[lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
- # two different shell functions defined in ltmain.sh;
- # decide which one to use based on capabilities of $DLLTOOL
- case `$DLLTOOL --help 2>&1` in
- *--identify-strict*)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
- ;;
- *)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
- ;;
- esac
- ;;
-*)
- # fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd=$ECHO
- ;;
-esac
-])
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
- [Command to associate shared and link libraries])
-])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
-
-
-# _LT_PATH_MANIFEST_TOOL
-# ----------------------
-# locate the manifest tool
-m4_defun([_LT_PATH_MANIFEST_TOOL],
-[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
- [lt_cv_path_mainfest_tool=no
- echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
- $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
- cat conftest.err >&AS_MESSAGE_LOG_FD
- if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
- fi
- rm -f conftest*])
-if test yes != "$lt_cv_path_mainfest_tool"; then
- MANIFEST_TOOL=:
-fi
-_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
-])# _LT_PATH_MANIFEST_TOOL
-
-
-# _LT_DLL_DEF_P([FILE])
-# ---------------------
-# True iff FILE is a Windows DLL '.def' file.
-# Keep in sync with func_dll_def_p in the libtool script
-AC_DEFUN([_LT_DLL_DEF_P],
-[dnl
- test DEF = "`$SED -n dnl
- -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
- -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
- -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
- -e q dnl Only consider the first "real" line
- $1`" dnl
-])# _LT_DLL_DEF_P
-
-
-# LT_LIB_M
-# --------
-# check for math library
-AC_DEFUN([LT_LIB_M],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-LIBM=
-case $host in
-*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
- # These system don't have libm, or don't need it
- ;;
-*-ncr-sysv4.3*)
- AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
- AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
- ;;
-*)
- AC_CHECK_LIB(m, cos, LIBM=-lm)
- ;;
-esac
-AC_SUBST([LIBM])
-])# LT_LIB_M
-
-# Old name:
-AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_CHECK_LIBM], [])
-
-
-# _LT_COMPILER_NO_RTTI([TAGNAME])
-# -------------------------------
-m4_defun([_LT_COMPILER_NO_RTTI],
-[m4_require([_LT_TAG_COMPILER])dnl
-
-_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
-
-if test yes = "$GCC"; then
- case $cc_basename in
- nvcc*)
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
- esac
-
- _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
- lt_cv_prog_compiler_rtti_exceptions,
- [-fno-rtti -fno-exceptions], [],
- [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
-fi
-_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
- [Compiler flag to turn off builtin functions])
-])# _LT_COMPILER_NO_RTTI
-
-
-# _LT_CMD_GLOBAL_SYMBOLS
-# ----------------------
-m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_PROG_CC])dnl
-AC_REQUIRE([AC_PROG_AWK])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-AC_REQUIRE([LT_PATH_LD])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-AC_MSG_CHECKING([command to parse $NM output from $compiler object])
-AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
-[
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[[BCDEGRST]]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[[BCDT]]'
- ;;
-cygwin* | mingw* | pw32* | cegcc*)
- symcode='[[ABCDGISTW]]'
- ;;
-hpux*)
- if test ia64 = "$host_cpu"; then
- symcode='[[ABCDEGRST]]'
- fi
- ;;
-irix* | nonstopux*)
- symcode='[[BCDEGRST]]'
- ;;
-osf*)
- symcode='[[BCDEGQRST]]'
- ;;
-solaris*)
- symcode='[[BDRT]]'
- ;;
-sco3.2v5*)
- symcode='[[DT]]'
- ;;
-sysv4.2uw2*)
- symcode='[[DT]]'
- ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
- symcode='[[ABDT]]'
- ;;
-sysv4)
- symcode='[[DFNSTU]]'
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
- symcode='[[ABCDGIRSTW]]' ;;
-esac
-
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Gets list of data symbols to import.
- lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
- # Adjust the below global symbol transforms to fixup imported variables.
- lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
- lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
- lt_c_name_lib_hook="\
- -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
- -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
-else
- # Disable hooks by default.
- lt_cv_sys_global_symbol_to_import=
- lt_cdecl_hook=
- lt_c_name_hook=
- lt_c_name_lib_hook=
-fi
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
-$lt_cdecl_hook\
-" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
-$lt_c_name_hook\
-" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
-
-# Transform an extracted symbol line into symbol name with lib prefix and
-# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
-$lt_c_name_lib_hook\
-" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
- opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
- symxfrm="\\1 $ac_symprfx\\2 \\2"
-
- # Write the raw and C identifiers.
- if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Fake it for dumpbin and say T for any non-static function,
- # D for any global variable and I for any imported variable.
- # Also find C++ and __fastcall symbols from MSVC++,
- # which start with @ or ?.
- lt_cv_sys_global_symbol_pipe="$AWK ['"\
-" {last_section=section; section=\$ 3};"\
-" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
-" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
-" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
-" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
-" \$ 0!~/External *\|/{next};"\
-" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-" {if(hide[section]) next};"\
-" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
-" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
-" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
-" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
-" ' prfx=^$ac_symprfx]"
- else
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
- fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
-
- rm -f conftest*
- cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
- if AC_TRY_EVAL(ac_compile); then
- # Now try to grab the symbols.
- nlist=conftest.nm
- $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD
- if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
- if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
-/* DATA imports from DLLs on WIN32 can't be const, because runtime
- relocations are performed -- see ld's documentation on pseudo-relocs. */
-# define LT@&t@_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data. */
-# define LT@&t@_DLSYM_CONST
-#else
-# define LT@&t@_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
- # Now generate the symbol file.
- eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
- cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols. */
-LT@&t@_DLSYM_CONST struct {
- const char *name;
- void *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[[]] =
-{
- { "@PROGRAM@", (void *) 0 },
-_LT_EOF
- $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
- cat <<\_LT_EOF >> conftest.$ac_ext
- {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- lt_globsym_save_LIBS=$LIBS
- lt_globsym_save_CFLAGS=$CFLAGS
- LIBS=conftstm.$ac_objext
- CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
- if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
- pipe_works=yes
- fi
- LIBS=$lt_globsym_save_LIBS
- CFLAGS=$lt_globsym_save_CFLAGS
- else
- echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
- fi
- else
- echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
- cat conftest.$ac_ext >&5
- fi
- rm -rf conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test yes = "$pipe_works"; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-])
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
- AC_MSG_RESULT(failed)
-else
- AC_MSG_RESULT(ok)
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
- nm_file_list_spec='@'
-fi
-
-_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
- [Take the output of nm and produce a listing of raw symbols and C names])
-_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
- [Transform the output of nm in a proper C declaration])
-_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
- [Transform the output of nm into a list of symbols to manually relocate])
-_LT_DECL([global_symbol_to_c_name_address],
- [lt_cv_sys_global_symbol_to_c_name_address], [1],
- [Transform the output of nm in a C name address pair])
-_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
- [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
- [Transform the output of nm in a C name address pair when lib prefix is needed])
-_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
- [The name lister interface])
-_LT_DECL([], [nm_file_list_spec], [1],
- [Specify filename containing input files for $NM])
-]) # _LT_CMD_GLOBAL_SYMBOLS
-
-
-# _LT_COMPILER_PIC([TAGNAME])
-# ---------------------------
-m4_defun([_LT_COMPILER_PIC],
-[m4_require([_LT_TAG_COMPILER])dnl
-_LT_TAGVAR(lt_prog_compiler_wl, $1)=
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=
-_LT_TAGVAR(lt_prog_compiler_static, $1)=
-
-m4_if([$1], [CXX], [
- # C++ specific cases for pic, static, wl, etc.
- if test yes = "$GXX"; then
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
- case $host_os in
- aix*)
- # All AIX code is PIC.
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- fi
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- m68k)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the '-m68020' flag to GCC prevents building anything better,
- # like '-m68040'.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
- mingw* | cygwin* | os2* | pw32* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- # Although the cygwin gcc ignores -fPIC, still need this for old-style
- # (--disable-auto-import) libraries
- m4_if([$1], [GCJ], [],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
- case $host_os in
- os2*)
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
- ;;
- esac
- ;;
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
- ;;
- *djgpp*)
- # DJGPP does not support shared libraries at all
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- ;;
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- _LT_TAGVAR(lt_prog_compiler_static, $1)=
- ;;
- interix[[3-9]]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
- fi
- ;;
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- ;;
- *qnx* | *nto*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- else
- case $host_os in
- aix[[4-9]]*)
- # All AIX code is PIC.
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- else
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
- chorus*)
- case $cc_basename in
- cxch68*)
- # Green Hills C++ Compiler
- # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
- ;;
- esac
- ;;
- mingw* | cygwin* | os2* | pw32* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- m4_if([$1], [GCJ], [],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
- ;;
- dgux*)
- case $cc_basename in
- ec++*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- ;;
- ghcx*)
- # Green Hills C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- *)
- ;;
- esac
- ;;
- freebsd* | dragonfly*)
- # FreeBSD uses GNU C++
- ;;
- hpux9* | hpux10* | hpux11*)
- case $cc_basename in
- CC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
- if test ia64 != "$host_cpu"; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
- fi
- ;;
- aCC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
- ;;
- esac
- ;;
- *)
- ;;
- esac
- ;;
- interix*)
- # This is c89, which is MS Visual C++ (no shared libs)
- # Anyone wants to do a port?
- ;;
- irix5* | irix6* | nonstopux*)
- case $cc_basename in
- CC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- # CC pic flag -KPIC is the default.
- ;;
- *)
- ;;
- esac
- ;;
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- KCC*)
- # KAI C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- ecpc* )
- # old Intel C++ for x86_64, which still supported -KPIC.
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- icpc* )
- # Intel C++, used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- pgCC* | pgcpp*)
- # Portland Group C++ compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- cxx*)
- # Compaq C++
- # Make sure the PIC flag is empty. It appears that all Alpha
- # Linux and Compaq Tru64 Unix objects are PIC.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
- # IBM XL 8.0, 9.0 on PPC and BlueGene
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- esac
- ;;
- esac
- ;;
- lynxos*)
- ;;
- m88k*)
- ;;
- mvs*)
- case $cc_basename in
- cxx*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
- ;;
- *)
- ;;
- esac
- ;;
- netbsd* | netbsdelf*-gnu)
- ;;
- *qnx* | *nto*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
- osf3* | osf4* | osf5*)
- case $cc_basename in
- KCC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
- ;;
- RCC*)
- # Rational C++ 2.4.1
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- cxx*)
- # Digital/Compaq C++
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # Make sure the PIC flag is empty. It appears that all Alpha
- # Linux and Compaq Tru64 Unix objects are PIC.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- *)
- ;;
- esac
- ;;
- psos*)
- ;;
- solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # Sun C++ 4.2, 5.x and Centerline C++
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- gcx*)
- # Green Hills C++ Compiler
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- ;;
- *)
- ;;
- esac
- ;;
- sunos4*)
- case $cc_basename in
- CC*)
- # Sun C++ 4.x
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- lcc*)
- # Lucid
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- ;;
- *)
- ;;
- esac
- ;;
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- case $cc_basename in
- CC*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- esac
- ;;
- tandem*)
- case $cc_basename in
- NCC*)
- # NonStop-UX NCC 3.20
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- ;;
- *)
- ;;
- esac
- ;;
- vxworks*)
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
- esac
- fi
-],
-[
- if test yes = "$GCC"; then
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
-
- case $host_os in
- aix*)
- # All AIX code is PIC.
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- fi
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- m68k)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the '-m68020' flag to GCC prevents building anything better,
- # like '-m68040'.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
-
- mingw* | cygwin* | pw32* | os2* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- # Although the cygwin gcc ignores -fPIC, still need this for old-style
- # (--disable-auto-import) libraries
- m4_if([$1], [GCJ], [],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
- case $host_os in
- os2*)
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
- ;;
-
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- _LT_TAGVAR(lt_prog_compiler_static, $1)=
- ;;
-
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
- ;;
-
- interix[[3-9]]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
-
- msdosdjgpp*)
- # Just because we use GCC doesn't mean we suddenly get shared libraries
- # on systems that don't support them.
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- enable_shared=no
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
- fi
- ;;
-
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- ;;
- esac
-
- case $cc_basename in
- nvcc*) # Cuda Compiler Driver 2.2
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
- if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
- fi
- ;;
- esac
- else
- # PORTME Check for flag to pass linker flags through the system compiler.
- case $host_os in
- aix*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- else
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
-
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
- case $cc_basename in
- nagfor*)
- # NAG Fortran compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- esac
- ;;
-
- mingw* | cygwin* | pw32* | os2* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- m4_if([$1], [GCJ], [],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
- case $host_os in
- os2*)
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
- ;;
- esac
- ;;
-
- hpux9* | hpux10* | hpux11*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
- # not for PA HP-UX.
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
- ;;
- esac
- # Is there a better lt_prog_compiler_static that works with the bundled CC?
- _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
- ;;
-
- irix5* | irix6* | nonstopux*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # PIC (with -KPIC) is the default.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- # old Intel for x86_64, which still supported -KPIC.
- ecc*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # flang / f18. f95 an alias for gfortran or flang on Debian
- flang* | f18* | f95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # icc used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- icc* | ifort*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- # Lahey Fortran 8.1.
- lf95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
- ;;
- nagfor*)
- # NAG Fortran compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- tcc*)
- # Fabrice Bellard et al's Tiny C Compiler
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
- # Portland Group compilers (*not* the Pentium gcc compiler,
- # which looks to be a dead project)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- ccc*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # All Alpha code is PIC.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
- xl* | bgxl* | bgf* | mpixl*)
- # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
- # Sun Fortran 8.3 passes all unrecognized flags to the linker
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
- ;;
- *Sun\ F* | *Sun*Fortran*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- ;;
- *Sun\ C*)
- # Sun C 5.9
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- ;;
- *Intel*\ [[CF]]*Compiler*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
- ;;
- *Portland\ Group*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
- esac
- ;;
- esac
- ;;
-
- newsos6)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
- ;;
-
- osf3* | osf4* | osf5*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- # All OSF/1 code is PIC.
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- rdos*)
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
- ;;
-
- solaris*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- case $cc_basename in
- f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
- *)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
- esac
- ;;
-
- sunos4*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- fi
- ;;
-
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- unicos*)
- _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
-
- uts4*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
- _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
- ;;
-
- *)
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
- ;;
- esac
- fi
-])
-case $host_os in
- # For platforms that do not support PIC, -DPIC is meaningless:
- *djgpp*)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)=
- ;;
- *)
- _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
- ;;
-esac
-
-AC_CACHE_CHECK([for $compiler option to produce PIC],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
-_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
- _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
- [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
- [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
- [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
- "" | " "*) ;;
- *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
- esac],
- [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
- _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
-fi
-_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
- [Additional compiler flags for building library objects])
-
-_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
- [How to pass a linker flag through the compiler])
-#
-# Check to make sure the static flag actually works.
-#
-wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
-_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
- _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
- $lt_tmp_static_flag,
- [],
- [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
-_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
- [Compiler flag to prevent dynamic linking])
-])# _LT_COMPILER_PIC
-
-
-# _LT_LINKER_SHLIBS([TAGNAME])
-# ----------------------------
-# See if the linker supports building shared libraries.
-m4_defun([_LT_LINKER_SHLIBS],
-[AC_REQUIRE([LT_PATH_LD])dnl
-AC_REQUIRE([LT_PATH_NM])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_DECL_SED])dnl
-m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
-m4_require([_LT_TAG_COMPILER])dnl
-AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
-m4_if([$1], [CXX], [
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
- case $host_os in
- aix[[4-9]]*)
- # If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to GNU nm, but means don't demangle to AIX nm.
- # Without the "-l" option, or with the "-B" option, AIX nm treats
- # weak defined symbols like other global defined symbols, whereas
- # GNU nm marks them as "W".
- # While the 'weak' keyword is ignored in the Export File, we need
- # it in the Import File for the 'aix-soname' feature, so we have
- # to replace the "-B" option with "-P" for AIX nm.
- if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
- fi
- ;;
- pw32*)
- _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
- ;;
- cygwin* | mingw* | cegcc*)
- case $cc_basename in
- cl*)
- _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- ;;
- *)
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
- ;;
- esac
- ;;
- linux* | k*bsd*-gnu | gnu*)
- _LT_TAGVAR(link_all_deplibs, $1)=no
- ;;
- *)
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- ;;
- esac
-], [
- runpath_var=
- _LT_TAGVAR(allow_undefined_flag, $1)=
- _LT_TAGVAR(always_export_symbols, $1)=no
- _LT_TAGVAR(archive_cmds, $1)=
- _LT_TAGVAR(archive_expsym_cmds, $1)=
- _LT_TAGVAR(compiler_needs_object, $1)=no
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
- _LT_TAGVAR(export_dynamic_flag_spec, $1)=
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(hardcode_automatic, $1)=no
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- _LT_TAGVAR(hardcode_minus_L, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
- _LT_TAGVAR(inherit_rpath, $1)=no
- _LT_TAGVAR(link_all_deplibs, $1)=unknown
- _LT_TAGVAR(module_cmds, $1)=
- _LT_TAGVAR(module_expsym_cmds, $1)=
- _LT_TAGVAR(old_archive_from_new_cmds, $1)=
- _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
- _LT_TAGVAR(thread_safe_flag_spec, $1)=
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- # include_expsyms should be a list of space-separated symbols to be *always*
- # included in the symbol list
- _LT_TAGVAR(include_expsyms, $1)=
- # exclude_expsyms can be an extended regexp of symbols to exclude
- # it will be wrapped by ' (' and ')$', so one must not match beginning or
- # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
- # as well as any symbol that contains 'd'.
- _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
- # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
- # platforms (ab)use it in PIC code, but their linkers get confused if
- # the symbol is explicitly referenced. Since portable code cannot
- # rely on this symbol name, it's probably fine to never include it in
- # preloaded symbol tables.
- # Exclude shared library initialization/finalization symbols.
-dnl Note also adjust exclude_expsyms for C++ above.
- extract_expsyms_cmds=
-
- case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test yes != "$GCC"; then
- with_gnu_ld=no
- fi
- ;;
- interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
- with_gnu_ld=yes
- ;;
- openbsd* | bitrig*)
- with_gnu_ld=no
- ;;
- linux* | k*bsd*-gnu | gnu*)
- _LT_TAGVAR(link_all_deplibs, $1)=no
- ;;
- esac
-
- _LT_TAGVAR(ld_shlibs, $1)=yes
-
- # On some targets, GNU ld is compatible enough with the native linker
- # that we're better off using the native interface for both.
- lt_use_gnu_ld_interface=no
- if test yes = "$with_gnu_ld"; then
- case $host_os in
- aix*)
- # The AIX port of GNU ld has always aspired to compatibility
- # with the native linker. However, as the warning in the GNU ld
- # block says, versions before 2.19.5* couldn't really create working
- # shared libraries, regardless of the interface used.
- case `$LD -v 2>&1` in
- *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
- *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
- *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- fi
-
- if test yes = "$lt_use_gnu_ld_interface"; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='$wl'
-
- # Set some defaults for GNU ld with shared library support. These
- # are reset later if shared libraries are not supported. Putting them
- # here allows them to be overridden if necessary.
- runpath_var=LD_RUN_PATH
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- supports_anon_versioning=no
- case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
- *GNU\ gold*) supports_anon_versioning=yes ;;
- *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix[[3-9]]*)
- # On AIX/PPC, the GNU linker is very broken
- if test ia64 != "$host_cpu"; then
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
- fi
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)=''
- ;;
- m68k)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- ;;
- esac
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- # Joseph Beckenbach says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
- # as there is no search path for DLLs.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=no
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
- _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
-
- if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file, use it as
- # is; otherwise, prepend EXPORTS...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
-
- os2*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- shrext_cmds=.dll
- _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- prefix_cmds="$SED"~
- if test EXPORTS = "`$SED 1q $export_symbols`"; then
- prefix_cmds="$prefix_cmds -e 1d";
- fi~
- prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
- cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- ;;
-
- interix[[3-9]]*)
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
- # Instead, shared libraries are loaded at an image base (0x10000000 by
- # default) and relocated if they conflict, which is a slow very memory
- # consuming and fragmenting process. To avoid this, we pick a random,
- # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
- # time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- ;;
-
- gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
- tmp_diet=no
- if test linux-dietlibc = "$host_os"; then
- case $cc_basename in
- diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
- esac
- fi
- if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
- && test no = "$tmp_diet"
- then
- tmp_addflag=' $pic_flag'
- tmp_sharedflag='-shared'
- case $cc_basename,$host_cpu in
- pgcc*) # Portland Group C compiler
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- tmp_addflag=' $pic_flag'
- ;;
- pgf77* | pgf90* | pgf95* | pgfortran*)
- # Portland Group f77 and f90 compilers
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- tmp_addflag=' $pic_flag -Mnomain' ;;
- ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
- tmp_addflag=' -i_dynamic' ;;
- efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
- tmp_addflag=' -i_dynamic -nofor_main' ;;
- ifc* | ifort*) # Intel Fortran compiler
- tmp_addflag=' -nofor_main' ;;
- lf95*) # Lahey Fortran 8.1
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- tmp_sharedflag='--shared' ;;
- nagfor*) # NAGFOR 5.3
- tmp_sharedflag='-Wl,-shared' ;;
- xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
- tmp_sharedflag='-qmkshrobj'
- tmp_addflag= ;;
- nvcc*) # Cuda Compiler Driver 2.2
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- _LT_TAGVAR(compiler_needs_object, $1)=yes
- ;;
- esac
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*) # Sun C 5.9
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- _LT_TAGVAR(compiler_needs_object, $1)=yes
- tmp_sharedflag='-G' ;;
- *Sun\ F*) # Sun Fortran 8.3
- tmp_sharedflag='-G' ;;
- esac
- _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-
- if test yes = "$supports_anon_versioning"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
- fi
-
- case $cc_basename in
- tcc*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
- ;;
- xlf* | bgf* | bgxlf* | mpixlf*)
- # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
- _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- if test yes = "$supports_anon_versioning"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
- fi
- ;;
- esac
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
- wlarc=
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- fi
- ;;
-
- solaris*)
- if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
- case `$LD -v 2>&1` in
- *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
- _LT_TAGVAR(ld_shlibs, $1)=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
-*** reliably create shared libraries on SCO systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- ;;
- *)
- # For security reasons, it is highly recommended that you always
- # use absolute paths for naming shared libraries, and exclude the
- # DT_RUNPATH tag from executables and libraries. But doing so
- # requires that you compile everything twice, which is a pain.
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- sunos4*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
-
- if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
- runpath_var=
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
- _LT_TAGVAR(export_dynamic_flag_spec, $1)=
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- _LT_TAGVAR(hardcode_direct, $1)=unsupported
- fi
- ;;
-
- aix[[4-9]]*)
- if test ia64 = "$host_cpu"; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=
- else
- # If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to GNU nm, but means don't demangle to AIX nm.
- # Without the "-l" option, or with the "-B" option, AIX nm treats
- # weak defined symbols like other global defined symbols, whereas
- # GNU nm marks them as "W".
- # While the 'weak' keyword is ignored in the Export File, we need
- # it in the Import File for the 'aix-soname' feature, so we have
- # to replace the "-B" option with "-P" for AIX nm.
- if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
- fi
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # have runtime linking enabled, and use it for executables.
- # For shared libraries, we enable/disable runtime linking
- # depending on the kind of the shared library created -
- # when "with_aix_soname,aix_use_runtimelinking" is:
- # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
- # "aix,yes" lib.so shared, rtl:yes, for executables
- # lib.a static archive
- # "both,no" lib.so.V(shr.o) shared, rtl:yes
- # lib.a(lib.so.V) shared, rtl:no, for executables
- # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a(lib.so.V) shared, rtl:no
- # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a static archive
- case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
- for ld_flag in $LDFLAGS; do
- if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
- # With aix-soname=svr4, we create the lib.so.V shared archives only,
- # so we don't have lib.a shared libs to link our executables.
- # We have to force runtime linking in this case.
- aix_use_runtimelinking=yes
- LDFLAGS="$LDFLAGS -Wl,-brtl"
- fi
- ;;
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- _LT_TAGVAR(archive_cmds, $1)=''
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
- case $with_aix_soname,$aix_use_runtimelinking in
- aix,*) ;; # traditional, no import file
- svr4,* | *,yes) # use import file
- # The Import File defines what to hardcode.
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=no
- ;;
- esac
-
- if test yes = "$GCC"; then
- case $host_os in aix4.[[012]]|aix4.[[012]].*)
- # We only want to do this on AIX 4.2 and lower, the check
- # below for broken collect2 doesn't work under 4.3+
- collect2name=`$CC -print-prog-name=collect2`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- _LT_TAGVAR(hardcode_direct, $1)=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- fi
- ;;
- esac
- shared_flag='-shared'
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag="$shared_flag "'$wl-G'
- fi
- # Need to ensure runtime linking is disabled for the traditional
- # shared library, or the linker may eventually find shared libraries
- # /with/ Import File - we do not want to mix them.
- shared_flag_aix='-shared'
- shared_flag_svr4='-shared $wl-G'
- else
- # not using gcc
- if test ia64 = "$host_cpu"; then
- # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
- # chokes on -Wl,-G. The following line is correct:
- shared_flag='-G'
- else
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- shared_flag='$wl-bM:SRE'
- fi
- shared_flag_aix='$wl-bM:SRE'
- shared_flag_svr4='$wl-G'
- fi
- fi
-
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
- # It seems that -bexpall does not export symbols beginning with
- # underscore (_), so it is better to generate a list of symbols to export.
- _LT_TAGVAR(always_export_symbols, $1)=yes
- if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
- # Determine the default libpath from the value encoded in an
- # empty executable.
- _LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
- else
- if test ia64 = "$host_cpu"; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
- _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
- else
- # Determine the default libpath from the value encoded in an
- # empty executable.
- _LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
- if test yes = "$with_gnu_ld"; then
- # We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
- else
- # Exported symbols can be pulled into shared objects from archives
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
- # -brtl affects multiple linker settings, -berok does not and is overridden later
- compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
- if test svr4 != "$with_aix_soname"; then
- # This is similar to how AIX traditionally builds its shared libraries.
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
- fi
- if test aix != "$with_aix_soname"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
- else
- # used by -dlpreopen to get the symbols
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
- fi
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
- fi
- fi
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)=''
- ;;
- m68k)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- ;;
- esac
- ;;
-
- bsdi[[45]]*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- case $cc_basename in
- cl*)
- # Native MSVC
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
- cp "$export_symbols" "$output_objdir/$soname.def";
- echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
- else
- $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
- # The linker will not automatically build a static lib if we build a DLL.
- # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
- # Don't use ranlib
- _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
- _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile=$lt_outputfile.exe
- lt_tool_outputfile=$lt_tool_outputfile.exe
- ;;
- esac~
- if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
- ;;
- *)
- # Assume MSVC wrapper
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
- # FIXME: Should let the user specify the lib program.
- _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
- _LT_DARWIN_LINKER_FEATURES($1)
- ;;
-
- dgux*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2.*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- hpux9*)
- if test yes = "$GCC"; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- else
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(hardcode_direct, $1)=yes
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- ;;
-
- hpux10*)
- if test yes,no = "$GCC,$with_gnu_ld"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
- else
- _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
- fi
- if test no = "$with_gnu_ld"; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- fi
- ;;
-
- hpux11*)
- if test yes,no = "$GCC,$with_gnu_ld"; then
- case $host_cpu in
- hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- else
- case $host_cpu in
- hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
- m4_if($1, [], [
- # Older versions of the 11.00 compiler do not understand -b yet
- # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
- _LT_LINKER_OPTION([if $CC understands -b],
- _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
- [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
- [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
- ;;
- esac
- fi
- if test no = "$with_gnu_ld"; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- case $host_cpu in
- hppa*64*|ia64*)
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
- *)
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- ;;
- esac
- fi
- ;;
-
- irix5* | irix6* | nonstopux*)
- if test yes = "$GCC"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- # Try to use the -exported_symbol ld option, if it does not
- # work, assume that -exports_file does not work either and
- # implicitly export all symbols.
- # This should be the same for all languages, so no per-tag cache variable.
- AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
- [lt_cv_irix_exported_symbol],
- [save_LDFLAGS=$LDFLAGS
- LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
- AC_LINK_IFELSE(
- [AC_LANG_SOURCE(
- [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
- [C++], [[int foo (void) { return 0; }]],
- [Fortran 77], [[
- subroutine foo
- end]],
- [Fortran], [[
- subroutine foo
- end]])])],
- [lt_cv_irix_exported_symbol=yes],
- [lt_cv_irix_exported_symbol=no])
- LDFLAGS=$save_LDFLAGS])
- if test yes = "$lt_cv_irix_exported_symbol"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
- fi
- _LT_TAGVAR(link_all_deplibs, $1)=no
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(inherit_rpath, $1)=yes
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
-
- linux*)
- case $cc_basename in
- tcc*)
- # Fabrice Bellard et al's Tiny C Compiler
- _LT_TAGVAR(ld_shlibs, $1)=yes
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- ;;
-
- netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- newsos6)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *nto* | *qnx*)
- ;;
-
- openbsd* | bitrig*)
- if test -f /usr/libexec/ld.so; then
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- fi
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- os2*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- shrext_cmds=.dll
- _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- prefix_cmds="$SED"~
- if test EXPORTS = "`$SED 1q $export_symbols`"; then
- prefix_cmds="$prefix_cmds -e 1d";
- fi~
- prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
- cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- ;;
-
- osf3*)
- if test yes = "$GCC"; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- else
- _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test yes = "$GCC"; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- else
- _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
-
- # Both c and cxx compiler support -rpath directly
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- ;;
-
- solaris*)
- _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
- if test yes = "$GCC"; then
- wlarc='$wl'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
- else
- case `$CC -V 2>&1` in
- *"Compilers 5.0"*)
- wlarc=''
- _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
- ;;
- *)
- wlarc='$wl'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
- ;;
- esac
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *)
- # The compiler driver will combine and reorder linker options,
- # but understands '-z linker_flag'. GCC discards it without '$wl',
- # but is careful enough not to reorder.
- # Supported since Solaris 2.6 (maybe 2.5.1?)
- if test yes = "$GCC"; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
- fi
- ;;
- esac
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
-
- sunos4*)
- if test sequent = "$host_vendor"; then
- # Use $CC to link under sequent, because it throws in some extra .o
- # files that make .init and .fini sections work.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- sysv4)
- case $host_vendor in
- sni)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
- ;;
- siemens)
- ## LD is ld it makes a PLAMLIB
- ## CC just makes a GrossModule.
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
- _LT_TAGVAR(hardcode_direct, $1)=no
- ;;
- motorola)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
- ;;
- esac
- runpath_var='LD_RUN_PATH'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- sysv4.3*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- _LT_TAGVAR(ld_shlibs, $1)=yes
- fi
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- runpath_var='LD_RUN_PATH'
-
- if test yes = "$GCC"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6*)
- # Note: We CANNOT use -z defs as we might desire, because we do not
- # link with -lc, and that would cause any symbols used from libc to
- # always be unresolved, which means just about no library would
- # ever link correctly. If we're not using GNU ld we use -z text
- # though, which does catch some bad symbols but isn't as heavy-handed
- # as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
- runpath_var='LD_RUN_PATH'
-
- if test yes = "$GCC"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- ;;
-
- uts4*)
- _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
-
- *)
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
-
- if test sni = "$host_vendor"; then
- case $host in
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
- ;;
- esac
- fi
- fi
-])
-AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
-test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
-_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
-
-_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
-_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
-_LT_DECL([], [extract_expsyms_cmds], [2],
- [The commands to extract the exported symbol list from a shared archive])
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
-x|xyes)
- # Assume -lc should be added
- _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
-
- if test yes,yes = "$GCC,$enable_shared"; then
- case $_LT_TAGVAR(archive_cmds, $1) in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- AC_CACHE_CHECK([whether -lc should be explicitly linked in],
- [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
- [$RM conftest*
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
- pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
- _LT_TAGVAR(allow_undefined_flag, $1)=
- if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
- then
- lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
- else
- lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- fi
- _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi
- $RM conftest*
- ])
- _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
- ;;
- esac
- fi
- ;;
-esac
-
-_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
- [Whether or not to add -lc for building shared libraries])
-_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
- [enable_shared_with_static_runtimes], [0],
- [Whether or not to disallow shared libs when runtime libs are static])
-_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
- [Compiler flag to allow reflexive dlopens])
-_LT_TAGDECL([], [whole_archive_flag_spec], [1],
- [Compiler flag to generate shared objects directly from archives])
-_LT_TAGDECL([], [compiler_needs_object], [1],
- [Whether the compiler copes with passing no objects directly])
-_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
- [Create an old-style archive from a shared archive])
-_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
- [Create a temporary old-style archive to link instead of a shared archive])
-_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
-_LT_TAGDECL([], [archive_expsym_cmds], [2])
-_LT_TAGDECL([], [module_cmds], [2],
- [Commands used to build a loadable module if different from building
- a shared archive.])
-_LT_TAGDECL([], [module_expsym_cmds], [2])
-_LT_TAGDECL([], [with_gnu_ld], [1],
- [Whether we are building with GNU ld or not])
-_LT_TAGDECL([], [allow_undefined_flag], [1],
- [Flag that allows shared libraries with undefined symbols to be built])
-_LT_TAGDECL([], [no_undefined_flag], [1],
- [Flag that enforces no undefined symbols])
-_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
- [Flag to hardcode $libdir into a binary during linking.
- This must work even if $libdir does not exist])
-_LT_TAGDECL([], [hardcode_libdir_separator], [1],
- [Whether we need a single "-rpath" flag with a separated argument])
-_LT_TAGDECL([], [hardcode_direct], [0],
- [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
- DIR into the resulting binary])
-_LT_TAGDECL([], [hardcode_direct_absolute], [0],
- [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
- DIR into the resulting binary and the resulting library dependency is
- "absolute", i.e impossible to change by setting $shlibpath_var if the
- library is relocated])
-_LT_TAGDECL([], [hardcode_minus_L], [0],
- [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
- into the resulting binary])
-_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
- [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
- into the resulting binary])
-_LT_TAGDECL([], [hardcode_automatic], [0],
- [Set to "yes" if building a shared library automatically hardcodes DIR
- into the library and all subsequent libraries and executables linked
- against it])
-_LT_TAGDECL([], [inherit_rpath], [0],
- [Set to yes if linker adds runtime paths of dependent libraries
- to runtime path list])
-_LT_TAGDECL([], [link_all_deplibs], [0],
- [Whether libtool must link a program against all its dependency libraries])
-_LT_TAGDECL([], [always_export_symbols], [0],
- [Set to "yes" if exported symbols are required])
-_LT_TAGDECL([], [export_symbols_cmds], [2],
- [The commands to list exported symbols])
-_LT_TAGDECL([], [exclude_expsyms], [1],
- [Symbols that should not be listed in the preloaded symbols])
-_LT_TAGDECL([], [include_expsyms], [1],
- [Symbols that must always be exported])
-_LT_TAGDECL([], [prelink_cmds], [2],
- [Commands necessary for linking programs (against libraries) with templates])
-_LT_TAGDECL([], [postlink_cmds], [2],
- [Commands necessary for finishing linking programs])
-_LT_TAGDECL([], [file_list_spec], [1],
- [Specify filename containing input files])
-dnl FIXME: Not yet implemented
-dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
-dnl [Compiler flag to generate thread safe objects])
-])# _LT_LINKER_SHLIBS
-
-
-# _LT_LANG_C_CONFIG([TAG])
-# ------------------------
-# Ensure that the configuration variables for a C compiler are suitably
-# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_C_CONFIG],
-[m4_require([_LT_DECL_EGREP])dnl
-lt_save_CC=$CC
-AC_LANG_PUSH(C)
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-_LT_TAG_COMPILER
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
- LT_SYS_DLOPEN_SELF
- _LT_CMD_STRIPLIB
-
- # Report what library types will actually be built
- AC_MSG_CHECKING([if libtool supports shared libraries])
- AC_MSG_RESULT([$can_build_shared])
-
- AC_MSG_CHECKING([whether to build shared libraries])
- test no = "$can_build_shared" && enable_shared=no
-
- # On AIX, shared libraries and static libraries use the same namespace, and
- # are all built from PIC.
- case $host_os in
- aix3*)
- test yes = "$enable_shared" && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
- aix[[4-9]]*)
- if test ia64 != "$host_cpu"; then
- case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
- yes,aix,yes) ;; # shared object as lib.so file only
- yes,svr4,*) ;; # shared object as lib.so archive member only
- yes,*) enable_static=no ;; # shared object in lib.a archive as well
- esac
- fi
- ;;
- esac
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- AC_MSG_RESULT([$enable_static])
-
- _LT_CONFIG($1)
-fi
-AC_LANG_POP
-CC=$lt_save_CC
-])# _LT_LANG_C_CONFIG
-
-
-# _LT_LANG_CXX_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a C++ compiler are suitably
-# defined. These variables are subsequently used by _LT_CONFIG to write
-# the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_CXX_CONFIG],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-m4_require([_LT_DECL_EGREP])dnl
-m4_require([_LT_PATH_MANIFEST_TOOL])dnl
-if test -n "$CXX" && ( test no != "$CXX" &&
- ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
- (test g++ != "$CXX"))); then
- AC_PROG_CXXCPP
-else
- _lt_caught_CXX_error=yes
-fi
-
-AC_LANG_PUSH(C++)
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(compiler_needs_object, $1)=no
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for C++ test sources.
-ac_ext=cpp
-
-# Object file extension for compiled C++ test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the CXX compiler isn't working. Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_caught_CXX_error"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="int some_variable = 0;"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_CFLAGS=$CFLAGS
- lt_save_LD=$LD
- lt_save_GCC=$GCC
- GCC=$GXX
- lt_save_with_gnu_ld=$with_gnu_ld
- lt_save_path_LD=$lt_cv_path_LD
- if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
- lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
- else
- $as_unset lt_cv_prog_gnu_ld
- fi
- if test -n "${lt_cv_path_LDCXX+set}"; then
- lt_cv_path_LD=$lt_cv_path_LDCXX
- else
- $as_unset lt_cv_path_LD
- fi
- test -z "${LDCXX+set}" || LD=$LDCXX
- CC=${CXX-"c++"}
- CFLAGS=$CXXFLAGS
- compiler=$CC
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
-
- if test -n "$compiler"; then
- # We don't want -fno-exception when compiling C++ code, so set the
- # no_builtin_flag separately
- if test yes = "$GXX"; then
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
- else
- _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
- fi
-
- if test yes = "$GXX"; then
- # Set up default GNU C++ configuration
-
- LT_PATH_LD
-
- # Check if GNU C++ uses GNU ld as the underlying linker, since the
- # archiving commands below assume that GNU ld is being used.
- if test yes = "$with_gnu_ld"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-
- # If archive_cmds runs LD, not CC, wlarc should be empty
- # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
- # investigate it a little bit more. (MM)
- wlarc='$wl'
-
- # ancient GNU ld didn't support --whole-archive et. al.
- if eval "`$CC -print-prog-name=ld` --help 2>&1" |
- $GREP 'no-whole-archive' > /dev/null; then
- _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
- else
- _LT_TAGVAR(whole_archive_flag_spec, $1)=
- fi
- else
- with_gnu_ld=no
- wlarc=
-
- # A generic and very simple default shared library creation
- # command for GNU C++ for the case where it uses the native
- # linker, instead of GNU ld. If possible, this setting should
- # overridden to take advantage of the native linker features on
- # the platform it is being used on.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- fi
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
-
- else
- GXX=no
- with_gnu_ld=no
- wlarc=
- fi
-
- # PORTME: fill in a description of your system's C++ link characteristics
- AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
- _LT_TAGVAR(ld_shlibs, $1)=yes
- case $host_os in
- aix3*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- aix[[4-9]]*)
- if test ia64 = "$host_cpu"; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=
- else
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # have runtime linking enabled, and use it for executables.
- # For shared libraries, we enable/disable runtime linking
- # depending on the kind of the shared library created -
- # when "with_aix_soname,aix_use_runtimelinking" is:
- # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
- # "aix,yes" lib.so shared, rtl:yes, for executables
- # lib.a static archive
- # "both,no" lib.so.V(shr.o) shared, rtl:yes
- # lib.a(lib.so.V) shared, rtl:no, for executables
- # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a(lib.so.V) shared, rtl:no
- # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a static archive
- case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
- for ld_flag in $LDFLAGS; do
- case $ld_flag in
- *-brtl*)
- aix_use_runtimelinking=yes
- break
- ;;
- esac
- done
- if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
- # With aix-soname=svr4, we create the lib.so.V shared archives only,
- # so we don't have lib.a shared libs to link our executables.
- # We have to force runtime linking in this case.
- aix_use_runtimelinking=yes
- LDFLAGS="$LDFLAGS -Wl,-brtl"
- fi
- ;;
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- _LT_TAGVAR(archive_cmds, $1)=''
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
- case $with_aix_soname,$aix_use_runtimelinking in
- aix,*) ;; # no import file
- svr4,* | *,yes) # use import file
- # The Import File defines what to hardcode.
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=no
- ;;
- esac
-
- if test yes = "$GXX"; then
- case $host_os in aix4.[[012]]|aix4.[[012]].*)
- # We only want to do this on AIX 4.2 and lower, the check
- # below for broken collect2 doesn't work under 4.3+
- collect2name=`$CC -print-prog-name=collect2`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- _LT_TAGVAR(hardcode_direct, $1)=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=
- fi
- esac
- shared_flag='-shared'
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag=$shared_flag' $wl-G'
- fi
- # Need to ensure runtime linking is disabled for the traditional
- # shared library, or the linker may eventually find shared libraries
- # /with/ Import File - we do not want to mix them.
- shared_flag_aix='-shared'
- shared_flag_svr4='-shared $wl-G'
- else
- # not using gcc
- if test ia64 = "$host_cpu"; then
- # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
- # chokes on -Wl,-G. The following line is correct:
- shared_flag='-G'
- else
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- shared_flag='$wl-bM:SRE'
- fi
- shared_flag_aix='$wl-bM:SRE'
- shared_flag_svr4='$wl-G'
- fi
- fi
-
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
- # It seems that -bexpall does not export symbols beginning with
- # underscore (_), so it is better to generate a list of symbols to
- # export.
- _LT_TAGVAR(always_export_symbols, $1)=yes
- if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- # The "-G" linker flag allows undefined symbols.
- _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
- # Determine the default libpath from the value encoded in an empty
- # executable.
- _LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
-
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
- else
- if test ia64 = "$host_cpu"; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
- _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
- _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
- else
- # Determine the default libpath from the value encoded in an
- # empty executable.
- _LT_SYS_MODULE_PATH_AIX([$1])
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
- if test yes = "$with_gnu_ld"; then
- # We only use this code for GNU lds that support --whole-archive.
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
- else
- # Exported symbols can be pulled into shared objects from archives
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
- fi
- _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
- _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
- # -brtl affects multiple linker settings, -berok does not and is overridden later
- compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
- if test svr4 != "$with_aix_soname"; then
- # This is similar to how AIX traditionally builds its shared
- # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
- fi
- if test aix != "$with_aix_soname"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
- else
- # used by -dlpreopen to get the symbols
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
- fi
- _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
- fi
- fi
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- # Joseph Beckenbach says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- chorus*)
- case $cc_basename in
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- case $GXX,$cc_basename in
- ,cl* | no,cl*)
- # Native MSVC
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=yes
- _LT_TAGVAR(file_list_spec, $1)='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
- _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
- cp "$export_symbols" "$output_objdir/$soname.def";
- echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
- else
- $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
- # The linker will not automatically build a static lib if we build a DLL.
- # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- # Don't use ranlib
- _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
- _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile=$lt_outputfile.exe
- lt_tool_outputfile=$lt_tool_outputfile.exe
- ;;
- esac~
- func_to_tool_file "$lt_outputfile"~
- if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
- ;;
- *)
- # g++
- # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
- # as there is no search path for DLLs.
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- _LT_TAGVAR(always_export_symbols, $1)=no
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-
- if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file, use it as
- # is; otherwise, prepend EXPORTS...
- _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
- darwin* | rhapsody*)
- _LT_DARWIN_LINKER_FEATURES($1)
- ;;
-
- os2*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
- _LT_TAGVAR(hardcode_minus_L, $1)=yes
- _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
- shrext_cmds=.dll
- _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- prefix_cmds="$SED"~
- if test EXPORTS = "`$SED 1q $export_symbols`"; then
- prefix_cmds="$prefix_cmds -e 1d";
- fi~
- prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
- cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
- _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
- ;;
-
- dgux*)
- case $cc_basename in
- ec++*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- ghcx*)
- # Green Hills C++ Compiler
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- freebsd2.*)
- # C++ shared libraries reported to be fairly broken before
- # switch to ELF
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- freebsd-elf*)
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- ;;
-
- freebsd* | dragonfly*)
- # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
- # conventions
- _LT_TAGVAR(ld_shlibs, $1)=yes
- ;;
-
- haiku*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
-
- hpux9*)
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
- # but as the default
- # location of the library.
-
- case $cc_basename in
- CC*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- aCC*)
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- ;;
- *)
- if test yes = "$GXX"; then
- _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- else
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- hpux10*|hpux11*)
- if test no = "$with_gnu_ld"; then
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- case $host_cpu in
- hppa*64*|ia64*)
- ;;
- *)
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- ;;
- esac
- fi
- case $host_cpu in
- hppa*64*|ia64*)
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- ;;
- *)
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
- # but as the default
- # location of the library.
- ;;
- esac
-
- case $cc_basename in
- CC*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- aCC*)
- case $host_cpu in
- hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- esac
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- ;;
- *)
- if test yes = "$GXX"; then
- if test no = "$with_gnu_ld"; then
- case $host_cpu in
- hppa*64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- ia64*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- ;;
- esac
- fi
- else
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- interix[[3-9]]*)
- _LT_TAGVAR(hardcode_direct, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
- # Instead, shared libraries are loaded at an image base (0x10000000 by
- # default) and relocated if they conflict, which is a slow very memory
- # consuming and fragmenting process. To avoid this, we pick a random,
- # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
- # time. Moving up from 0x10000000 also allows more sbrk(2) space.
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- ;;
- irix5* | irix6*)
- case $cc_basename in
- CC*)
- # SGI C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
-
- # Archives containing C++ object files must be created using
- # "CC -ar", where "CC" is the IRIX C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
- ;;
- *)
- if test yes = "$GXX"; then
- if test no = "$with_gnu_ld"; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- else
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
- fi
- fi
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- ;;
- esac
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
- _LT_TAGVAR(inherit_rpath, $1)=yes
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- KCC*)
- # Kuck and Associates, Inc. (KAI) C++ Compiler
-
- # KCC will only create a shared library if the output file
- # ends with ".so" (or ".sl" for HP-UX), so rename the library
- # to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
-
- # Archives containing C++ object files must be created using
- # "CC -Bstatic", where "CC" is the KAI C++ compiler.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
- ;;
- icpc* | ecpc* )
- # Intel C++
- with_gnu_ld=yes
- # version 8.0 and above of icpc choke on multiply defined symbols
- # if we add $predep_objects and $postdep_objects, however 7.1 and
- # earlier do not add the objects themselves.
- case `$CC -V 2>&1` in
- *"Version 7."*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- ;;
- *) # Version 8.0 or newer
- tmp_idyn=
- case $host_cpu in
- ia64*) tmp_idyn=' -i_dynamic';;
- esac
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- ;;
- esac
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
- ;;
- pgCC* | pgcpp*)
- # Portland Group C++ compiler
- case `$CC -V` in
- *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
- _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
- compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
- _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
- $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
- $RANLIB $oldlib'
- _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
- rm -rf $tpldir~
- $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
- $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- ;;
- *) # Version 6 and above use weak symbols
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- ;;
- esac
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- ;;
- cxx*)
- # Compaq C++
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
-
- runpath_var=LD_RUN_PATH
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
- ;;
- xl* | mpixl* | bgxl*)
- # IBM XL 8.0 on PPC, with GNU ld
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
- _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- if test yes = "$supports_anon_versioning"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
- fi
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*)
- # Sun C++ 5.9
- _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- _LT_TAGVAR(compiler_needs_object, $1)=yes
-
- # Not sure whether something based on
- # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
- # would be better.
- output_verbose_link_cmd='func_echo_all'
-
- # Archives containing C++ object files must be created using
- # "CC -xar", where "CC" is the Sun C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
- ;;
- esac
- ;;
- esac
- ;;
-
- lynxos*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- m88k*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- mvs*)
- case $cc_basename in
- cxx*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- netbsd*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
- wlarc=
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- fi
- # Workaround some broken pre-1.5 toolchains
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
- ;;
-
- *nto* | *qnx*)
- _LT_TAGVAR(ld_shlibs, $1)=yes
- ;;
-
- openbsd* | bitrig*)
- if test -f /usr/libexec/ld.so; then
- _LT_TAGVAR(hardcode_direct, $1)=yes
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
- _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
- fi
- output_verbose_link_cmd=func_echo_all
- else
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
-
- osf3* | osf4* | osf5*)
- case $cc_basename in
- KCC*)
- # Kuck and Associates, Inc. (KAI) C++ Compiler
-
- # KCC will only create a shared library if the output file
- # ends with ".so" (or ".sl" for HP-UX), so rename the library
- # to its proper name (with version) after linking.
- _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Archives containing C++ object files must be created using
- # the KAI C++ compiler.
- case $host in
- osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
- *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
- esac
- ;;
- RCC*)
- # Rational C++ 2.4.1
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- cxx*)
- case $host in
- osf3*)
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- ;;
- *)
- _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
- echo "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
- $RM $lib.exp'
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
- ;;
- esac
-
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- #
- # There doesn't appear to be a way to prevent this compiler from
- # explicitly linking system object files so we need to strip them
- # from the output so that they don't get included in the library
- # dependencies.
- output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
- ;;
- *)
- if test yes,no = "$GXX,$with_gnu_ld"; then
- _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
- case $host in
- osf3*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- ;;
- esac
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=:
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
-
- else
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- fi
- ;;
- esac
- ;;
-
- psos*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- sunos4*)
- case $cc_basename in
- CC*)
- # Sun C++ 4.x
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- lcc*)
- # Lucid
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- solaris*)
- case $cc_basename in
- CC* | sunCC*)
- # Sun C++ 4.2, 5.x and Centerline C++
- _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
- _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
- _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *)
- # The compiler driver will combine and reorder linker options,
- # but understands '-z linker_flag'.
- # Supported since Solaris 2.6 (maybe 2.5.1?)
- _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
- ;;
- esac
- _LT_TAGVAR(link_all_deplibs, $1)=yes
-
- output_verbose_link_cmd='func_echo_all'
-
- # Archives containing C++ object files must be created using
- # "CC -xar", where "CC" is the Sun C++ compiler. This is
- # necessary to make sure instantiated templates are included
- # in the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
- ;;
- gcx*)
- # Green Hills C++ Compiler
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
-
- # The C++ compiler must be used to create the archive.
- _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
- ;;
- *)
- # GNU C++ compiler with Solaris linker
- if test yes,no = "$GXX,$with_gnu_ld"; then
- _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
- if $CC --version | $GREP -v '^2\.7' > /dev/null; then
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
- else
- # g++ 2.7 appears to require '-G' NOT '-shared' on this
- # platform.
- _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
- _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
-
- # Commands to make compiler produce verbose output that lists
- # what "hidden" libraries, object files and flags are used when
- # linking a shared library.
- output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
- fi
-
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
- case $host_os in
- solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
- *)
- _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
- ;;
- esac
- fi
- ;;
- esac
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
- _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- runpath_var='LD_RUN_PATH'
-
- case $cc_basename in
- CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- ;;
-
- sysv5* | sco3.2v5* | sco5v6*)
- # Note: We CANNOT use -z defs as we might desire, because we do not
- # link with -lc, and that would cause any symbols used from libc to
- # always be unresolved, which means just about no library would
- # ever link correctly. If we're not using GNU ld we use -z text
- # though, which does catch some bad symbols but isn't as heavy-handed
- # as -z defs.
- _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
- _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
- _LT_TAGVAR(archive_cmds_need_lc, $1)=no
- _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
- _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
- _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
- _LT_TAGVAR(link_all_deplibs, $1)=yes
- _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
- runpath_var='LD_RUN_PATH'
-
- case $cc_basename in
- CC*)
- _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
- '"$_LT_TAGVAR(old_archive_cmds, $1)"
- _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
- '"$_LT_TAGVAR(reload_cmds, $1)"
- ;;
- *)
- _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- ;;
-
- tandem*)
- case $cc_basename in
- NCC*)
- # NonStop-UX NCC 3.20
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
- ;;
-
- vxworks*)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
-
- *)
- # FIXME: insert proper C++ library support
- _LT_TAGVAR(ld_shlibs, $1)=no
- ;;
- esac
-
- AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
- test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
-
- _LT_TAGVAR(GCC, $1)=$GXX
- _LT_TAGVAR(LD, $1)=$LD
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_SYS_HIDDEN_LIBDEPS($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
- LDCXX=$LD
- LD=$lt_save_LD
- GCC=$lt_save_GCC
- with_gnu_ld=$lt_save_with_gnu_ld
- lt_cv_path_LDCXX=$lt_cv_path_LD
- lt_cv_path_LD=$lt_save_path_LD
- lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
- lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
-fi # test yes != "$_lt_caught_CXX_error"
-
-AC_LANG_POP
-])# _LT_LANG_CXX_CONFIG
-
-
-# _LT_FUNC_STRIPNAME_CNF
-# ----------------------
-# func_stripname_cnf prefix suffix name
-# strip PREFIX and SUFFIX off of NAME.
-# PREFIX and SUFFIX must not contain globbing or regex special
-# characters, hashes, percent signs, but SUFFIX may contain a leading
-# dot (in which case that matches only a dot).
-#
-# This function is identical to the (non-XSI) version of func_stripname,
-# except this one can be used by m4 code that may be executed by configure,
-# rather than the libtool script.
-m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
-AC_REQUIRE([_LT_DECL_SED])
-AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
-func_stripname_cnf ()
-{
- case @S|@2 in
- .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
- *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
- esac
-} # func_stripname_cnf
-])# _LT_FUNC_STRIPNAME_CNF
-
-
-# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
-# ---------------------------------
-# Figure out "hidden" library dependencies from verbose
-# compiler output when linking a shared library.
-# Parse the compiler output and extract the necessary
-# objects, libraries and library flags.
-m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
-[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
-AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
-# Dependencies to place before and after the object being linked:
-_LT_TAGVAR(predep_objects, $1)=
-_LT_TAGVAR(postdep_objects, $1)=
-_LT_TAGVAR(predeps, $1)=
-_LT_TAGVAR(postdeps, $1)=
-_LT_TAGVAR(compiler_lib_search_path, $1)=
-
-dnl we can't use the lt_simple_compile_test_code here,
-dnl because it contains code intended for an executable,
-dnl not a library. It's possible we should let each
-dnl tag define a new lt_????_link_test_code variable,
-dnl but it's only used here...
-m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
-int a;
-void foo (void) { a = 0; }
-_LT_EOF
-], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
-class Foo
-{
-public:
- Foo (void) { a = 0; }
-private:
- int a;
-};
-_LT_EOF
-], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
- subroutine foo
- implicit none
- integer*4 a
- a=0
- return
- end
-_LT_EOF
-], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
- subroutine foo
- implicit none
- integer a
- a=0
- return
- end
-_LT_EOF
-], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
-public class foo {
- private int a;
- public void bar (void) {
- a = 0;
- }
-};
-_LT_EOF
-], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
-package foo
-func foo() {
-}
-_LT_EOF
-])
-
-_lt_libdeps_save_CFLAGS=$CFLAGS
-case "$CC $CFLAGS " in #(
-*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
-*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
-*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
-esac
-
-dnl Parse the compiler output and extract the necessary
-dnl objects, libraries and library flags.
-if AC_TRY_EVAL(ac_compile); then
- # Parse the compiler output and extract the necessary
- # objects, libraries and library flags.
-
- # Sentinel used to keep track of whether or not we are before
- # the conftest object file.
- pre_test_object_deps_done=no
-
- for p in `eval "$output_verbose_link_cmd"`; do
- case $prev$p in
-
- -L* | -R* | -l*)
- # Some compilers place space between "-{L,R}" and the path.
- # Remove the space.
- if test x-L = "$p" ||
- test x-R = "$p"; then
- prev=$p
- continue
- fi
-
- # Expand the sysroot to ease extracting the directories later.
- if test -z "$prev"; then
- case $p in
- -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
- -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
- -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
- esac
- fi
- case $p in
- =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
- esac
- if test no = "$pre_test_object_deps_done"; then
- case $prev in
- -L | -R)
- # Internal compiler library paths should come after those
- # provided the user. The postdeps already come after the
- # user supplied libs so there is no need to process them.
- if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
- _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
- else
- _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
- fi
- ;;
- # The "-l" case would never come before the object being
- # linked, so don't bother handling this case.
- esac
- else
- if test -z "$_LT_TAGVAR(postdeps, $1)"; then
- _LT_TAGVAR(postdeps, $1)=$prev$p
- else
- _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
- fi
- fi
- prev=
- ;;
-
- *.lto.$objext) ;; # Ignore GCC LTO objects
- *.$objext)
- # This assumes that the test object file only shows up
- # once in the compiler output.
- if test "$p" = "conftest.$objext"; then
- pre_test_object_deps_done=yes
- continue
- fi
-
- if test no = "$pre_test_object_deps_done"; then
- if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
- _LT_TAGVAR(predep_objects, $1)=$p
- else
- _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
- fi
- else
- if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
- _LT_TAGVAR(postdep_objects, $1)=$p
- else
- _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
- fi
- fi
- ;;
-
- *) ;; # Ignore the rest.
-
- esac
- done
-
- # Clean up.
- rm -f a.out a.exe
-else
- echo "libtool.m4: error: problem compiling $1 test program"
-fi
-
-$RM -f confest.$objext
-CFLAGS=$_lt_libdeps_save_CFLAGS
-
-# PORTME: override above test on systems where it is broken
-m4_if([$1], [CXX],
-[case $host_os in
-interix[[3-9]]*)
- # Interix 3.5 installs completely hosed .la files for C++, so rather than
- # hack all around it, let's just trust "g++" to DTRT.
- _LT_TAGVAR(predep_objects,$1)=
- _LT_TAGVAR(postdep_objects,$1)=
- _LT_TAGVAR(postdeps,$1)=
- ;;
-esac
-])
-
-case " $_LT_TAGVAR(postdeps, $1) " in
-*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
-esac
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=
-if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
- _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
-fi
-_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
- [The directories searched by this compiler when creating a shared library])
-_LT_TAGDECL([], [predep_objects], [1],
- [Dependencies to place before and after the objects being linked to
- create a shared library])
-_LT_TAGDECL([], [postdep_objects], [1])
-_LT_TAGDECL([], [predeps], [1])
-_LT_TAGDECL([], [postdeps], [1])
-_LT_TAGDECL([], [compiler_lib_search_path], [1],
- [The library search path used internally by the compiler when linking
- a shared library])
-])# _LT_SYS_HIDDEN_LIBDEPS
-
-
-# _LT_LANG_F77_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for a Fortran 77 compiler are
-# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_F77_CONFIG],
-[AC_LANG_PUSH(Fortran 77)
-if test -z "$F77" || test no = "$F77"; then
- _lt_disable_F77=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for f77 test sources.
-ac_ext=f
-
-# Object file extension for compiled f77 test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the F77 compiler isn't working. Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_disable_F77"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="\
- subroutine t
- return
- end
-"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code="\
- program t
- end
-"
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_GCC=$GCC
- lt_save_CFLAGS=$CFLAGS
- CC=${F77-"f77"}
- CFLAGS=$FFLAGS
- compiler=$CC
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
- GCC=$G77
- if test -n "$compiler"; then
- AC_MSG_CHECKING([if libtool supports shared libraries])
- AC_MSG_RESULT([$can_build_shared])
-
- AC_MSG_CHECKING([whether to build shared libraries])
- test no = "$can_build_shared" && enable_shared=no
-
- # On AIX, shared libraries and static libraries use the same namespace, and
- # are all built from PIC.
- case $host_os in
- aix3*)
- test yes = "$enable_shared" && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
- aix[[4-9]]*)
- if test ia64 != "$host_cpu"; then
- case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
- yes,aix,yes) ;; # shared object as lib.so file only
- yes,svr4,*) ;; # shared object as lib.so archive member only
- yes,*) enable_static=no ;; # shared object in lib.a archive as well
- esac
- fi
- ;;
- esac
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- AC_MSG_RESULT([$enable_static])
-
- _LT_TAGVAR(GCC, $1)=$G77
- _LT_TAGVAR(LD, $1)=$LD
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- GCC=$lt_save_GCC
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_F77"
-
-AC_LANG_POP
-])# _LT_LANG_F77_CONFIG
-
-
-# _LT_LANG_FC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for a Fortran compiler are
-# suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_FC_CONFIG],
-[AC_LANG_PUSH(Fortran)
-
-if test -z "$FC" || test no = "$FC"; then
- _lt_disable_FC=yes
-fi
-
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-_LT_TAGVAR(allow_undefined_flag, $1)=
-_LT_TAGVAR(always_export_symbols, $1)=no
-_LT_TAGVAR(archive_expsym_cmds, $1)=
-_LT_TAGVAR(export_dynamic_flag_spec, $1)=
-_LT_TAGVAR(hardcode_direct, $1)=no
-_LT_TAGVAR(hardcode_direct_absolute, $1)=no
-_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
-_LT_TAGVAR(hardcode_libdir_separator, $1)=
-_LT_TAGVAR(hardcode_minus_L, $1)=no
-_LT_TAGVAR(hardcode_automatic, $1)=no
-_LT_TAGVAR(inherit_rpath, $1)=no
-_LT_TAGVAR(module_cmds, $1)=
-_LT_TAGVAR(module_expsym_cmds, $1)=
-_LT_TAGVAR(link_all_deplibs, $1)=unknown
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-_LT_TAGVAR(no_undefined_flag, $1)=
-_LT_TAGVAR(whole_archive_flag_spec, $1)=
-_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
-
-# Source file extension for fc test sources.
-ac_ext=${ac_fc_srcext-f}
-
-# Object file extension for compiled fc test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# No sense in running all these tests if we already determined that
-# the FC compiler isn't working. Some variables (like enable_shared)
-# are currently assumed to apply to all compilers on this platform,
-# and will be corrupted by setting them based on a non-working compiler.
-if test yes != "$_lt_disable_FC"; then
- # Code to be used in simple compile tests
- lt_simple_compile_test_code="\
- subroutine t
- return
- end
-"
-
- # Code to be used in simple link tests
- lt_simple_link_test_code="\
- program t
- end
-"
-
- # ltmain only uses $CC for tagged configurations so make sure $CC is set.
- _LT_TAG_COMPILER
-
- # save warnings/boilerplate of simple test code
- _LT_COMPILER_BOILERPLATE
- _LT_LINKER_BOILERPLATE
-
- # Allow CC to be a program name with arguments.
- lt_save_CC=$CC
- lt_save_GCC=$GCC
- lt_save_CFLAGS=$CFLAGS
- CC=${FC-"f95"}
- CFLAGS=$FCFLAGS
- compiler=$CC
- GCC=$ac_cv_fc_compiler_gnu
-
- _LT_TAGVAR(compiler, $1)=$CC
- _LT_CC_BASENAME([$compiler])
-
- if test -n "$compiler"; then
- AC_MSG_CHECKING([if libtool supports shared libraries])
- AC_MSG_RESULT([$can_build_shared])
-
- AC_MSG_CHECKING([whether to build shared libraries])
- test no = "$can_build_shared" && enable_shared=no
-
- # On AIX, shared libraries and static libraries use the same namespace, and
- # are all built from PIC.
- case $host_os in
- aix3*)
- test yes = "$enable_shared" && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
- aix[[4-9]]*)
- if test ia64 != "$host_cpu"; then
- case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
- yes,aix,yes) ;; # shared object as lib.so file only
- yes,svr4,*) ;; # shared object as lib.so archive member only
- yes,*) enable_static=no ;; # shared object in lib.a archive as well
- esac
- fi
- ;;
- esac
- AC_MSG_RESULT([$enable_shared])
-
- AC_MSG_CHECKING([whether to build static libraries])
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- AC_MSG_RESULT([$enable_static])
-
- _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
- _LT_TAGVAR(LD, $1)=$LD
-
- ## CAVEAT EMPTOR:
- ## There is no encapsulation within the following macros, do not change
- ## the running order or otherwise move them around unless you know exactly
- ## what you are doing...
- _LT_SYS_HIDDEN_LIBDEPS($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_SYS_DYNAMIC_LINKER($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
- fi # test -n "$compiler"
-
- GCC=$lt_save_GCC
- CC=$lt_save_CC
- CFLAGS=$lt_save_CFLAGS
-fi # test yes != "$_lt_disable_FC"
-
-AC_LANG_POP
-])# _LT_LANG_FC_CONFIG
-
-
-# _LT_LANG_GCJ_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Java Compiler compiler
-# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_GCJ_CONFIG],
-[AC_REQUIRE([LT_PROG_GCJ])dnl
-AC_LANG_SAVE
-
-# Source file extension for Java test sources.
-ac_ext=java
-
-# Object file extension for compiled Java test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="class foo {}"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GCJ-"gcj"}
-CFLAGS=$GCJFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# GCJ did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GCJ_CONFIG
-
-
-# _LT_LANG_GO_CONFIG([TAG])
-# --------------------------
-# Ensure that the configuration variables for the GNU Go compiler
-# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_GO_CONFIG],
-[AC_REQUIRE([LT_PROG_GO])dnl
-AC_LANG_SAVE
-
-# Source file extension for Go test sources.
-ac_ext=go
-
-# Object file extension for compiled Go test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="package main; func main() { }"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='package main; func main() { }'
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=yes
-CC=${GOC-"gccgo"}
-CFLAGS=$GOFLAGS
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_TAGVAR(LD, $1)=$LD
-_LT_CC_BASENAME([$compiler])
-
-# Go did not exist at the time GCC didn't implicitly link libc in.
-_LT_TAGVAR(archive_cmds_need_lc, $1)=no
-
-_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
-_LT_TAGVAR(reload_flag, $1)=$reload_flag
-_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
-
-if test -n "$compiler"; then
- _LT_COMPILER_NO_RTTI($1)
- _LT_COMPILER_PIC($1)
- _LT_COMPILER_C_O($1)
- _LT_COMPILER_FILE_LOCKS($1)
- _LT_LINKER_SHLIBS($1)
- _LT_LINKER_HARDCODE_LIBPATH($1)
-
- _LT_CONFIG($1)
-fi
-
-AC_LANG_RESTORE
-
-GCC=$lt_save_GCC
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_GO_CONFIG
-
-
-# _LT_LANG_RC_CONFIG([TAG])
-# -------------------------
-# Ensure that the configuration variables for the Windows resource compiler
-# are suitably defined. These variables are subsequently used by _LT_CONFIG
-# to write the compiler configuration to 'libtool'.
-m4_defun([_LT_LANG_RC_CONFIG],
-[AC_REQUIRE([LT_PROG_RC])dnl
-AC_LANG_SAVE
-
-# Source file extension for RC test sources.
-ac_ext=rc
-
-# Object file extension for compiled RC test sources.
-objext=o
-_LT_TAGVAR(objext, $1)=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
-
-# Code to be used in simple link tests
-lt_simple_link_test_code=$lt_simple_compile_test_code
-
-# ltmain only uses $CC for tagged configurations so make sure $CC is set.
-_LT_TAG_COMPILER
-
-# save warnings/boilerplate of simple test code
-_LT_COMPILER_BOILERPLATE
-_LT_LINKER_BOILERPLATE
-
-# Allow CC to be a program name with arguments.
-lt_save_CC=$CC
-lt_save_CFLAGS=$CFLAGS
-lt_save_GCC=$GCC
-GCC=
-CC=${RC-"windres"}
-CFLAGS=
-compiler=$CC
-_LT_TAGVAR(compiler, $1)=$CC
-_LT_CC_BASENAME([$compiler])
-_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
-
-if test -n "$compiler"; then
- :
- _LT_CONFIG($1)
-fi
-
-GCC=$lt_save_GCC
-AC_LANG_RESTORE
-CC=$lt_save_CC
-CFLAGS=$lt_save_CFLAGS
-])# _LT_LANG_RC_CONFIG
-
-
-# LT_PROG_GCJ
-# -----------
-AC_DEFUN([LT_PROG_GCJ],
-[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
- [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
- [AC_CHECK_TOOL(GCJ, gcj,)
- test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
- AC_SUBST(GCJFLAGS)])])[]dnl
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
-
-
-# LT_PROG_GO
-# ----------
-AC_DEFUN([LT_PROG_GO],
-[AC_CHECK_TOOL(GOC, gccgo,)
-])
-
-
-# LT_PROG_RC
-# ----------
-AC_DEFUN([LT_PROG_RC],
-[AC_CHECK_TOOL(RC, windres,)
-])
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_RC], [])
-
-
-# _LT_DECL_EGREP
-# --------------
-# If we don't have a new enough Autoconf to choose the best grep
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_EGREP],
-[AC_REQUIRE([AC_PROG_EGREP])dnl
-AC_REQUIRE([AC_PROG_FGREP])dnl
-test -z "$GREP" && GREP=grep
-_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
-_LT_DECL([], [EGREP], [1], [An ERE matcher])
-_LT_DECL([], [FGREP], [1], [A literal string matcher])
-dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
-AC_SUBST([GREP])
-])
-
-
-# _LT_DECL_OBJDUMP
-# --------------
-# If we don't have a new enough Autoconf to choose the best objdump
-# available, choose the one first in the user's PATH.
-m4_defun([_LT_DECL_OBJDUMP],
-[AC_CHECK_TOOL(OBJDUMP, objdump, false)
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
-AC_SUBST([OBJDUMP])
-])
-
-# _LT_DECL_DLLTOOL
-# ----------------
-# Ensure DLLTOOL variable is set.
-m4_defun([_LT_DECL_DLLTOOL],
-[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
-AC_SUBST([DLLTOOL])
-])
-
-# _LT_DECL_SED
-# ------------
-# Check for a fully-functional sed program, that truncates
-# as few characters as possible. Prefer GNU sed if found.
-m4_defun([_LT_DECL_SED],
-[AC_PROG_SED
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
-_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
- [Sed that helps us avoid accidentally triggering echo(1) options like -n])
-])# _LT_DECL_SED
-
-m4_ifndef([AC_PROG_SED], [
-# NOTE: This macro has been submitted for inclusion into #
-# GNU Autoconf as AC_PROG_SED. When it is available in #
-# a released version of Autoconf we should remove this #
-# macro and use it instead. #
-
-m4_defun([AC_PROG_SED],
-[AC_MSG_CHECKING([for a sed that does not truncate output])
-AC_CACHE_VAL(lt_cv_path_SED,
-[# Loop through the user's path and test for sed and gsed.
-# Then use that list of sed's as ones to test for truncation.
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for lt_ac_prog in sed gsed; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
- lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
- fi
- done
- done
-done
-IFS=$as_save_IFS
-lt_ac_max=0
-lt_ac_count=0
-# Add /usr/xpg4/bin/sed as it is typically found on Solaris
-# along with /bin/sed that truncates output.
-for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
- test ! -f "$lt_ac_sed" && continue
- cat /dev/null > conftest.in
- lt_ac_count=0
- echo $ECHO_N "0123456789$ECHO_C" >conftest.in
- # Check for GNU sed and select it if it is found.
- if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
- lt_cv_path_SED=$lt_ac_sed
- break
- fi
- while true; do
- cat conftest.in conftest.in >conftest.tmp
- mv conftest.tmp conftest.in
- cp conftest.in conftest.nl
- echo >>conftest.nl
- $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
- cmp -s conftest.out conftest.nl || break
- # 10000 chars as input seems more than enough
- test 10 -lt "$lt_ac_count" && break
- lt_ac_count=`expr $lt_ac_count + 1`
- if test "$lt_ac_count" -gt "$lt_ac_max"; then
- lt_ac_max=$lt_ac_count
- lt_cv_path_SED=$lt_ac_sed
- fi
- done
-done
-])
-SED=$lt_cv_path_SED
-AC_SUBST([SED])
-AC_MSG_RESULT([$SED])
-])#AC_PROG_SED
-])#m4_ifndef
-
-# Old name:
-AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([LT_AC_PROG_SED], [])
-
-
-# _LT_CHECK_SHELL_FEATURES
-# ------------------------
-# Find out whether the shell is Bourne or XSI compatible,
-# or has some other useful features.
-m4_defun([_LT_CHECK_SHELL_FEATURES],
-[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
- lt_unset=unset
-else
- lt_unset=false
-fi
-_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
- # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
- lt_SP2NL='tr \040 \012'
- lt_NL2SP='tr \015\012 \040\040'
- ;;
- *) # EBCDIC based system
- lt_SP2NL='tr \100 \n'
- lt_NL2SP='tr \r\n \100\100'
- ;;
-esac
-_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
-_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
-])# _LT_CHECK_SHELL_FEATURES
-
-
-# _LT_PATH_CONVERSION_FUNCTIONS
-# -----------------------------
-# Determine what file name conversion functions should be used by
-# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
-# for certain cross-compile configurations and native mingw.
-m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-AC_REQUIRE([AC_CANONICAL_BUILD])dnl
-AC_MSG_CHECKING([how to convert $build file names to $host format])
-AC_CACHE_VAL(lt_cv_to_host_file_cmd,
-[case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
- ;;
- esac
- ;;
- *-*-cygwin* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
- ;;
- esac
- ;;
- * ) # unhandled hosts (and "normal" native builds)
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
-esac
-])
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
-_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
- [0], [convert $build file names to $host format])dnl
-
-AC_MSG_CHECKING([how to convert $build file names to toolchain format])
-AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
-[#assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
- ;;
- esac
- ;;
-esac
-])
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
-_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
- [0], [convert $build files to toolchain format])dnl
-])# _LT_PATH_CONVERSION_FUNCTIONS
-
-# Helper functions for option handling. -*- Autoconf -*-
-#
-# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
-# Foundation, Inc.
-# Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 8 ltoptions.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
-
-
-# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
-# ------------------------------------------
-m4_define([_LT_MANGLE_OPTION],
-[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
-
-
-# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
-# ---------------------------------------
-# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
-# matching handler defined, dispatch to it. Other OPTION-NAMEs are
-# saved as a flag.
-m4_define([_LT_SET_OPTION],
-[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
-m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
- _LT_MANGLE_DEFUN([$1], [$2]),
- [m4_warning([Unknown $1 option '$2'])])[]dnl
-])
-
-
-# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
-# ------------------------------------------------------------
-# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
-m4_define([_LT_IF_OPTION],
-[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
-
-
-# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
-# -------------------------------------------------------
-# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
-# are set.
-m4_define([_LT_UNLESS_OPTIONS],
-[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
- [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
- [m4_define([$0_found])])])[]dnl
-m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
-])[]dnl
-])
-
-
-# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
-# ----------------------------------------
-# OPTION-LIST is a space-separated list of Libtool options associated
-# with MACRO-NAME. If any OPTION has a matching handler declared with
-# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
-# the unknown option and exit.
-m4_defun([_LT_SET_OPTIONS],
-[# Set options
-m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
- [_LT_SET_OPTION([$1], _LT_Option)])
-
-m4_if([$1],[LT_INIT],[
- dnl
- dnl Simply set some default values (i.e off) if boolean options were not
- dnl specified:
- _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
- ])
- _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
- ])
- dnl
- dnl If no reference was made to various pairs of opposing options, then
- dnl we run the default mode handler for the pair. For example, if neither
- dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
- dnl archives by default:
- _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
- _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
- _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
- _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
- [_LT_ENABLE_FAST_INSTALL])
- _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
- [_LT_WITH_AIX_SONAME([aix])])
- ])
-])# _LT_SET_OPTIONS
-
-
-
-# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
-# -----------------------------------------
-m4_define([_LT_MANGLE_DEFUN],
-[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
-
-
-# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
-# -----------------------------------------------
-m4_define([LT_OPTION_DEFINE],
-[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
-])# LT_OPTION_DEFINE
-
-
-# dlopen
-# ------
-LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
-])
-
-AU_DEFUN([AC_LIBTOOL_DLOPEN],
-[_LT_SET_OPTION([LT_INIT], [dlopen])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'dlopen' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
-
-
-# win32-dll
-# ---------
-# Declare package support for building win32 dll's.
-LT_OPTION_DEFINE([LT_INIT], [win32-dll],
-[enable_win32_dll=yes
-
-case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
- AC_CHECK_TOOL(AS, as, false)
- AC_CHECK_TOOL(DLLTOOL, dlltool, false)
- AC_CHECK_TOOL(OBJDUMP, objdump, false)
- ;;
-esac
-
-test -z "$AS" && AS=as
-_LT_DECL([], [AS], [1], [Assembler program])dnl
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
-])# win32-dll
-
-AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
-[AC_REQUIRE([AC_CANONICAL_HOST])dnl
-_LT_SET_OPTION([LT_INIT], [win32-dll])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'win32-dll' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
-
-
-# _LT_ENABLE_SHARED([DEFAULT])
-# ----------------------------
-# implement the --enable-shared flag, and supports the 'shared' and
-# 'disable-shared' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_SHARED],
-[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([shared],
- [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
- [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_shared=yes ;;
- no) enable_shared=no ;;
- *)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
-
- _LT_DECL([build_libtool_libs], [enable_shared], [0],
- [Whether or not to build shared libraries])
-])# _LT_ENABLE_SHARED
-
-LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
-])
-
-AC_DEFUN([AC_DISABLE_SHARED],
-[_LT_SET_OPTION([LT_INIT], [disable-shared])
-])
-
-AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
-AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_SHARED], [])
-dnl AC_DEFUN([AM_DISABLE_SHARED], [])
-
-
-
-# _LT_ENABLE_STATIC([DEFAULT])
-# ----------------------------
-# implement the --enable-static flag, and support the 'static' and
-# 'disable-static' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_STATIC],
-[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([static],
- [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
- [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_static=yes ;;
- no) enable_static=no ;;
- *)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
-
- _LT_DECL([build_old_libs], [enable_static], [0],
- [Whether or not to build static libraries])
-])# _LT_ENABLE_STATIC
-
-LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
-
-# Old names:
-AC_DEFUN([AC_ENABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
-])
-
-AC_DEFUN([AC_DISABLE_STATIC],
-[_LT_SET_OPTION([LT_INIT], [disable-static])
-])
-
-AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
-AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AM_ENABLE_STATIC], [])
-dnl AC_DEFUN([AM_DISABLE_STATIC], [])
-
-
-
-# _LT_ENABLE_FAST_INSTALL([DEFAULT])
-# ----------------------------------
-# implement the --enable-fast-install flag, and support the 'fast-install'
-# and 'disable-fast-install' LT_INIT options.
-# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
-m4_define([_LT_ENABLE_FAST_INSTALL],
-[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
-AC_ARG_ENABLE([fast-install],
- [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
- [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
- [p=${PACKAGE-default}
- case $enableval in
- yes) enable_fast_install=yes ;;
- no) enable_fast_install=no ;;
- *)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
-
-_LT_DECL([fast_install], [enable_fast_install], [0],
- [Whether or not to optimize for fast installation])dnl
-])# _LT_ENABLE_FAST_INSTALL
-
-LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
-LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
-
-# Old names:
-AU_DEFUN([AC_ENABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the 'fast-install' option into LT_INIT's first parameter.])
-])
-
-AU_DEFUN([AC_DISABLE_FAST_INSTALL],
-[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you put
-the 'disable-fast-install' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
-dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
-
-
-# _LT_WITH_AIX_SONAME([DEFAULT])
-# ----------------------------------
-# implement the --with-aix-soname flag, and support the `aix-soname=aix'
-# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
-# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
-m4_define([_LT_WITH_AIX_SONAME],
-[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
-shared_archive_member_spec=
-case $host,$enable_shared in
-power*-*-aix[[5-9]]*,yes)
- AC_MSG_CHECKING([which variant of shared library versioning to provide])
- AC_ARG_WITH([aix-soname],
- [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
- [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
- [case $withval in
- aix|svr4|both)
- ;;
- *)
- AC_MSG_ERROR([Unknown argument to --with-aix-soname])
- ;;
- esac
- lt_cv_with_aix_soname=$with_aix_soname],
- [AC_CACHE_VAL([lt_cv_with_aix_soname],
- [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
- with_aix_soname=$lt_cv_with_aix_soname])
- AC_MSG_RESULT([$with_aix_soname])
- if test aix != "$with_aix_soname"; then
- # For the AIX way of multilib, we name the shared archive member
- # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
- # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
- # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
- # the AIX toolchain works better with OBJECT_MODE set (default 32).
- if test 64 = "${OBJECT_MODE-32}"; then
- shared_archive_member_spec=shr_64
- else
- shared_archive_member_spec=shr
- fi
- fi
- ;;
-*)
- with_aix_soname=aix
- ;;
-esac
-
-_LT_DECL([], [shared_archive_member_spec], [0],
- [Shared archive member basename, for filename based shared library versioning on AIX])dnl
-])# _LT_WITH_AIX_SONAME
-
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
-LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
-
-
-# _LT_WITH_PIC([MODE])
-# --------------------
-# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
-# LT_INIT options.
-# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
-m4_define([_LT_WITH_PIC],
-[AC_ARG_WITH([pic],
- [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
- [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
- [lt_p=${PACKAGE-default}
- case $withval in
- yes|no) pic_mode=$withval ;;
- *)
- pic_mode=default
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for lt_pkg in $withval; do
- IFS=$lt_save_ifs
- if test "X$lt_pkg" = "X$lt_p"; then
- pic_mode=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac],
- [pic_mode=m4_default([$1], [default])])
-
-_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
-])# _LT_WITH_PIC
-
-LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
-LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
-
-# Old name:
-AU_DEFUN([AC_LIBTOOL_PICMODE],
-[_LT_SET_OPTION([LT_INIT], [pic-only])
-AC_DIAGNOSE([obsolete],
-[$0: Remove this warning and the call to _LT_SET_OPTION when you
-put the 'pic-only' option into LT_INIT's first parameter.])
-])
-
-dnl aclocal-1.4 backwards compatibility:
-dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
-
-
-m4_define([_LTDL_MODE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
- [m4_define([_LTDL_MODE], [nonrecursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [recursive],
- [m4_define([_LTDL_MODE], [recursive])])
-LT_OPTION_DEFINE([LTDL_INIT], [subproject],
- [m4_define([_LTDL_MODE], [subproject])])
-
-m4_define([_LTDL_TYPE], [])
-LT_OPTION_DEFINE([LTDL_INIT], [installable],
- [m4_define([_LTDL_TYPE], [installable])])
-LT_OPTION_DEFINE([LTDL_INIT], [convenience],
- [m4_define([_LTDL_TYPE], [convenience])])
-
-# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
-#
-# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
-# Foundation, Inc.
-# Written by Gary V. Vaughan, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 6 ltsugar.m4
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
-
-
-# lt_join(SEP, ARG1, [ARG2...])
-# -----------------------------
-# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
-# associated separator.
-# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
-# versions in m4sugar had bugs.
-m4_define([lt_join],
-[m4_if([$#], [1], [],
- [$#], [2], [[$2]],
- [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
-m4_define([_lt_join],
-[m4_if([$#$2], [2], [],
- [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
-
-
-# lt_car(LIST)
-# lt_cdr(LIST)
-# ------------
-# Manipulate m4 lists.
-# These macros are necessary as long as will still need to support
-# Autoconf-2.59, which quotes differently.
-m4_define([lt_car], [[$1]])
-m4_define([lt_cdr],
-[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
- [$#], 1, [],
- [m4_dquote(m4_shift($@))])])
-m4_define([lt_unquote], $1)
-
-
-# lt_append(MACRO-NAME, STRING, [SEPARATOR])
-# ------------------------------------------
-# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
-# Note that neither SEPARATOR nor STRING are expanded; they are appended
-# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
-# No SEPARATOR is output if MACRO-NAME was previously undefined (different
-# than defined and empty).
-#
-# This macro is needed until we can rely on Autoconf 2.62, since earlier
-# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
-m4_define([lt_append],
-[m4_define([$1],
- m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
-
-
-
-# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
-# ----------------------------------------------------------
-# Produce a SEP delimited list of all paired combinations of elements of
-# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
-# has the form PREFIXmINFIXSUFFIXn.
-# Needed until we can rely on m4_combine added in Autoconf 2.62.
-m4_define([lt_combine],
-[m4_if(m4_eval([$# > 3]), [1],
- [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
-[[m4_foreach([_Lt_prefix], [$2],
- [m4_foreach([_Lt_suffix],
- ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
- [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
-
-
-# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
-# -----------------------------------------------------------------------
-# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
-# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
-m4_define([lt_if_append_uniq],
-[m4_ifdef([$1],
- [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
- [lt_append([$1], [$2], [$3])$4],
- [$5])],
- [lt_append([$1], [$2], [$3])$4])])
-
-
-# lt_dict_add(DICT, KEY, VALUE)
-# -----------------------------
-m4_define([lt_dict_add],
-[m4_define([$1($2)], [$3])])
-
-
-# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
-# --------------------------------------------
-m4_define([lt_dict_add_subkey],
-[m4_define([$1($2:$3)], [$4])])
-
-
-# lt_dict_fetch(DICT, KEY, [SUBKEY])
-# ----------------------------------
-m4_define([lt_dict_fetch],
-[m4_ifval([$3],
- m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
- m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
-
-
-# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
-# -----------------------------------------------------------------
-m4_define([lt_if_dict_fetch],
-[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
- [$5],
- [$6])])
-
-
-# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
-# --------------------------------------------------------------
-m4_define([lt_dict_filter],
-[m4_if([$5], [], [],
- [lt_join(m4_quote(m4_default([$4], [[, ]])),
- lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
- [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
-])
-
-# ltversion.m4 -- version numbers -*- Autoconf -*-
-#
-# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
-# Written by Scott James Remnant, 2004
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# @configure_input@
-
-# serial 4179 ltversion.m4
-# This file is part of GNU Libtool
-
-m4_define([LT_PACKAGE_VERSION], [2.4.6])
-m4_define([LT_PACKAGE_REVISION], [2.4.6])
-
-AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.6'
-macro_revision='2.4.6'
-_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
-_LT_DECL(, macro_revision, 0)
-])
-
-# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
-#
-# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
-# Foundation, Inc.
-# Written by Scott James Remnant, 2004.
-#
-# This file is free software; the Free Software Foundation gives
-# unlimited permission to copy and/or distribute it, with or without
-# modifications, as long as this notice is preserved.
-
-# serial 5 lt~obsolete.m4
-
-# These exist entirely to fool aclocal when bootstrapping libtool.
-#
-# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
-# which have later been changed to m4_define as they aren't part of the
-# exported API, or moved to Autoconf or Automake where they belong.
-#
-# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
-# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
-# using a macro with the same name in our local m4/libtool.m4 it'll
-# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
-# and doesn't know about Autoconf macros at all.)
-#
-# So we provide this file, which has a silly filename so it's always
-# included after everything else. This provides aclocal with the
-# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
-# because those macros already exist, or will be overwritten later.
-# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
-#
-# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
-# Yes, that means every name once taken will need to remain here until
-# we give up compatibility with versions before 1.7, at which point
-# we need to keep only those names which we still refer to.
-
-# This is to help aclocal find these macros, as it can't see m4_define.
-AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
-
-m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
-m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
-m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
-m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
-m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
-m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
-m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
-m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
-m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
-m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
-m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
-m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
-m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
-m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
-m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
-m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
-m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
-m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
-m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
-m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
-m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
-m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
-m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
-m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
-m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
-m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
-m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
-m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
-m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
-m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
-m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
-m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
-m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
-m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
-m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
-m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
-m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
-m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
-m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
-m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
-m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
-m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
-m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
-m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
-m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
-m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
-m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
-m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
-m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
-m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
-m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
-m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
-m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
-m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
-m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
-
diff --git a/art/icon-243x273.gif b/art/icon-243x273.gif
new file mode 100644
index 0000000000..e1cdfd0b51
Binary files /dev/null and b/art/icon-243x273.gif differ
diff --git a/art/icon-80x90.gif b/art/icon-80x90.gif
new file mode 100644
index 0000000000..ebb2390005
Binary files /dev/null and b/art/icon-80x90.gif differ
diff --git a/art/sqlite370.svg b/art/sqlite370.svg
new file mode 100644
index 0000000000..9a050b593d
--- /dev/null
+++ b/art/sqlite370.svg
@@ -0,0 +1,104 @@
+
+
+
+
diff --git a/auto.def b/auto.def
new file mode 100644
index 0000000000..8ed5996373
--- /dev/null
+++ b/auto.def
@@ -0,0 +1,47 @@
+#!/do/not/tclsh
+# ^^^ help out editors which guess this file's content type.
+#
+# This is the main autosetup-compatible configure script for the
+# SQLite project.
+#
+# This script and all of its dependencies must be kept compatible with
+# JimTCL, a copy of which is included in this source tree as
+# ./autosetup/jimsh0.c. The number of incompatibilities between
+# canonical TCL and JimTCL is very low and alternative formulations of
+# incompatible constructs have, so far, been easy to find.
+#
+# JimTCL: https://jim.tcl.tk
+#
+
+use sqlite-config
+sqlite-configure canonical {
+ proj-if-opt-truthy dev {
+ # --enable-dev needs to come early so that the downstream tests
+ # which check for the following flags use their updated state.
+ proj-opt-set all 1
+ proj-opt-set debug 1
+ proj-opt-set amalgamation 0
+ define CFLAGS [get-env CFLAGS {-O0 -g}]
+ # -------------^^^^^^^ intentionally using [get-env] instead of
+ # [proj-get-env] here because [sqlite-setup-default-cflags] uses
+ # [proj-get-env] and we want this to supercede that.
+ }
+ sqlite-check-common-bins ;# must come before [sqlite-handle-wasi-sdk]
+ sqlite-handle-wasi-sdk ;# must run relatively early, as it changes the environment
+ sqlite-check-common-system-deps
+
+ proj-define-for-opt amalgamation USE_AMALGAMATION "Use amalgamation for builds?"
+
+ proj-define-for-opt gcov USE_GCOV "Use gcov?"
+
+ proj-define-for-opt test-status TSTRNNR_OPTS \
+ "test-runner flags:" {--status} {}
+
+ proj-define-for-opt linemacros AMALGAMATION_LINE_MACROS \
+ "Use #line macros in the amalgamation:"
+
+ define LINK_TOOLS_DYNAMICALLY [proj-opt-was-provided dynlink-tools]
+
+ sqlite-handle-tcl
+ sqlite-handle-emsdk
+}
diff --git a/autoconf/INSTALL b/autoconf/INSTALL
deleted file mode 100644
index a1e89e18ad..0000000000
--- a/autoconf/INSTALL
+++ /dev/null
@@ -1,370 +0,0 @@
-Installation Instructions
-*************************
-
-Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
-Inc.
-
- Copying and distribution of this file, with or without modification,
-are permitted in any medium without royalty provided the copyright
-notice and this notice are preserved. This file is offered as-is,
-without warranty of any kind.
-
-Basic Installation
-==================
-
- Briefly, the shell commands `./configure; make; make install' should
-configure, build, and install this package. The following
-more-detailed instructions are generic; see the `README' file for
-instructions specific to this package. Some packages provide this
-`INSTALL' file but do not implement all of the features documented
-below. The lack of an optional feature in a given package is not
-necessarily a bug. More recommendations for GNU packages can be found
-in *note Makefile Conventions: (standards)Makefile Conventions.
-
- The `configure' shell script attempts to guess correct values for
-various system-dependent variables used during compilation. It uses
-those values to create a `Makefile' in each directory of the package.
-It may also create one or more `.h' files containing system-dependent
-definitions. Finally, it creates a shell script `config.status' that
-you can run in the future to recreate the current configuration, and a
-file `config.log' containing compiler output (useful mainly for
-debugging `configure').
-
- It can also use an optional file (typically called `config.cache'
-and enabled with `--cache-file=config.cache' or simply `-C') that saves
-the results of its tests to speed up reconfiguring. Caching is
-disabled by default to prevent problems with accidental use of stale
-cache files.
-
- If you need to do unusual things to compile the package, please try
-to figure out how `configure' could check whether to do them, and mail
-diffs or instructions to the address given in the `README' so they can
-be considered for the next release. If you are using the cache, and at
-some point `config.cache' contains results you don't want to keep, you
-may remove or edit it.
-
- The file `configure.ac' (or `configure.in') is used to create
-`configure' by a program called `autoconf'. You need `configure.ac' if
-you want to change it or regenerate `configure' using a newer version
-of `autoconf'.
-
- The simplest way to compile this package is:
-
- 1. `cd' to the directory containing the package's source code and type
- `./configure' to configure the package for your system.
-
- Running `configure' might take a while. While running, it prints
- some messages telling which features it is checking for.
-
- 2. Type `make' to compile the package.
-
- 3. Optionally, type `make check' to run any self-tests that come with
- the package, generally using the just-built uninstalled binaries.
-
- 4. Type `make install' to install the programs and any data files and
- documentation. When installing into a prefix owned by root, it is
- recommended that the package be configured and built as a regular
- user, and only the `make install' phase executed with root
- privileges.
-
- 5. Optionally, type `make installcheck' to repeat any self-tests, but
- this time using the binaries in their final installed location.
- This target does not install anything. Running this target as a
- regular user, particularly if the prior `make install' required
- root privileges, verifies that the installation completed
- correctly.
-
- 6. You can remove the program binaries and object files from the
- source code directory by typing `make clean'. To also remove the
- files that `configure' created (so you can compile the package for
- a different kind of computer), type `make distclean'. There is
- also a `make maintainer-clean' target, but that is intended mainly
- for the package's developers. If you use it, you may have to get
- all sorts of other programs in order to regenerate files that came
- with the distribution.
-
- 7. Often, you can also type `make uninstall' to remove the installed
- files again. In practice, not all packages have tested that
- uninstallation works correctly, even though it is required by the
- GNU Coding Standards.
-
- 8. Some packages, particularly those that use Automake, provide `make
- distcheck', which can by used by developers to test that all other
- targets like `make install' and `make uninstall' work correctly.
- This target is generally not run by end users.
-
-Compilers and Options
-=====================
-
- Some systems require unusual options for compilation or linking that
-the `configure' script does not know about. Run `./configure --help'
-for details on some of the pertinent environment variables.
-
- You can give `configure' initial values for configuration parameters
-by setting variables in the command line or in the environment. Here
-is an example:
-
- ./configure CC=c99 CFLAGS=-g LIBS=-lposix
-
- *Note Defining Variables::, for more details.
-
-Compiling For Multiple Architectures
-====================================
-
- You can compile the package for more than one kind of computer at the
-same time, by placing the object files for each architecture in their
-own directory. To do this, you can use GNU `make'. `cd' to the
-directory where you want the object files and executables to go and run
-the `configure' script. `configure' automatically checks for the
-source code in the directory that `configure' is in and in `..'. This
-is known as a "VPATH" build.
-
- With a non-GNU `make', it is safer to compile the package for one
-architecture at a time in the source code directory. After you have
-installed the package for one architecture, use `make distclean' before
-reconfiguring for another architecture.
-
- On MacOS X 10.5 and later systems, you can create libraries and
-executables that work on multiple system types--known as "fat" or
-"universal" binaries--by specifying multiple `-arch' options to the
-compiler but only a single `-arch' option to the preprocessor. Like
-this:
-
- ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
- CPP="gcc -E" CXXCPP="g++ -E"
-
- This is not guaranteed to produce working output in all cases, you
-may have to build one architecture at a time and combine the results
-using the `lipo' tool if you have problems.
-
-Installation Names
-==================
-
- By default, `make install' installs the package's commands under
-`/usr/local/bin', include files under `/usr/local/include', etc. You
-can specify an installation prefix other than `/usr/local' by giving
-`configure' the option `--prefix=PREFIX', where PREFIX must be an
-absolute file name.
-
- You can specify separate installation prefixes for
-architecture-specific files and architecture-independent files. If you
-pass the option `--exec-prefix=PREFIX' to `configure', the package uses
-PREFIX as the prefix for installing programs and libraries.
-Documentation and other data files still use the regular prefix.
-
- In addition, if you use an unusual directory layout you can give
-options like `--bindir=DIR' to specify different values for particular
-kinds of files. Run `configure --help' for a list of the directories
-you can set and what kinds of files go in them. In general, the
-default for these options is expressed in terms of `${prefix}', so that
-specifying just `--prefix' will affect all of the other directory
-specifications that were not explicitly provided.
-
- The most portable way to affect installation locations is to pass the
-correct locations to `configure'; however, many packages provide one or
-both of the following shortcuts of passing variable assignments to the
-`make install' command line to change installation locations without
-having to reconfigure or recompile.
-
- The first method involves providing an override variable for each
-affected directory. For example, `make install
-prefix=/alternate/directory' will choose an alternate location for all
-directory configuration variables that were expressed in terms of
-`${prefix}'. Any directories that were specified during `configure',
-but not in terms of `${prefix}', must each be overridden at install
-time for the entire installation to be relocated. The approach of
-makefile variable overrides for each directory variable is required by
-the GNU Coding Standards, and ideally causes no recompilation.
-However, some platforms have known limitations with the semantics of
-shared libraries that end up requiring recompilation when using this
-method, particularly noticeable in packages that use GNU Libtool.
-
- The second method involves providing the `DESTDIR' variable. For
-example, `make install DESTDIR=/alternate/directory' will prepend
-`/alternate/directory' before all installation names. The approach of
-`DESTDIR' overrides is not required by the GNU Coding Standards, and
-does not work on platforms that have drive letters. On the other hand,
-it does better at avoiding recompilation issues, and works well even
-when some directory options were not specified in terms of `${prefix}'
-at `configure' time.
-
-Optional Features
-=================
-
- If the package supports it, you can cause programs to be installed
-with an extra prefix or suffix on their names by giving `configure' the
-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
-
- Some packages pay attention to `--enable-FEATURE' options to
-`configure', where FEATURE indicates an optional part of the package.
-They may also pay attention to `--with-PACKAGE' options, where PACKAGE
-is something like `gnu-as' or `x' (for the X Window System). The
-`README' should mention any `--enable-' and `--with-' options that the
-package recognizes.
-
- For packages that use the X Window System, `configure' can usually
-find the X include and library files automatically, but if it doesn't,
-you can use the `configure' options `--x-includes=DIR' and
-`--x-libraries=DIR' to specify their locations.
-
- Some packages offer the ability to configure how verbose the
-execution of `make' will be. For these packages, running `./configure
---enable-silent-rules' sets the default to minimal output, which can be
-overridden with `make V=1'; while running `./configure
---disable-silent-rules' sets the default to verbose, which can be
-overridden with `make V=0'.
-
-Particular systems
-==================
-
- On HP-UX, the default C compiler is not ANSI C compatible. If GNU
-CC is not installed, it is recommended to use the following options in
-order to use an ANSI C compiler:
-
- ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
-
-and if that doesn't work, install pre-built binaries of GCC for HP-UX.
-
- HP-UX `make' updates targets which have the same time stamps as
-their prerequisites, which makes it generally unusable when shipped
-generated files such as `configure' are involved. Use GNU `make'
-instead.
-
- On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
-parse its `' header file. The option `-nodtk' can be used as
-a workaround. If GNU CC is not installed, it is therefore recommended
-to try
-
- ./configure CC="cc"
-
-and if that doesn't work, try
-
- ./configure CC="cc -nodtk"
-
- On Solaris, don't put `/usr/ucb' early in your `PATH'. This
-directory contains several dysfunctional programs; working variants of
-these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
-in your `PATH', put it _after_ `/usr/bin'.
-
- On Haiku, software installed for all users goes in `/boot/common',
-not `/usr/local'. It is recommended to use the following options:
-
- ./configure --prefix=/boot/common
-
-Specifying the System Type
-==========================
-
- There may be some features `configure' cannot figure out
-automatically, but needs to determine by the type of machine the package
-will run on. Usually, assuming the package is built to be run on the
-_same_ architectures, `configure' can figure that out, but if it prints
-a message saying it cannot guess the machine type, give it the
-`--build=TYPE' option. TYPE can either be a short name for the system
-type, such as `sun4', or a canonical name which has the form:
-
- CPU-COMPANY-SYSTEM
-
-where SYSTEM can have one of these forms:
-
- OS
- KERNEL-OS
-
- See the file `config.sub' for the possible values of each field. If
-`config.sub' isn't included in this package, then this package doesn't
-need to know the machine type.
-
- If you are _building_ compiler tools for cross-compiling, you should
-use the option `--target=TYPE' to select the type of system they will
-produce code for.
-
- If you want to _use_ a cross compiler, that generates code for a
-platform different from the build platform, you should specify the
-"host" platform (i.e., that on which the generated programs will
-eventually be run) with `--host=TYPE'.
-
-Sharing Defaults
-================
-
- If you want to set default values for `configure' scripts to share,
-you can create a site shell script called `config.site' that gives
-default values for variables like `CC', `cache_file', and `prefix'.
-`configure' looks for `PREFIX/share/config.site' if it exists, then
-`PREFIX/etc/config.site' if it exists. Or, you can set the
-`CONFIG_SITE' environment variable to the location of the site script.
-A warning: not all `configure' scripts look for a site script.
-
-Defining Variables
-==================
-
- Variables not defined in a site shell script can be set in the
-environment passed to `configure'. However, some packages may run
-configure again during the build, and the customized values of these
-variables may be lost. In order to avoid this problem, you should set
-them in the `configure' command line, using `VAR=value'. For example:
-
- ./configure CC=/usr/local2/bin/gcc
-
-causes the specified `gcc' to be used as the C compiler (unless it is
-overridden in the site shell script).
-
-Unfortunately, this technique does not work for `CONFIG_SHELL' due to
-an Autoconf bug. Until the bug is fixed you can use this workaround:
-
- CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
-
-`configure' Invocation
-======================
-
- `configure' recognizes the following options to control how it
-operates.
-
-`--help'
-`-h'
- Print a summary of all of the options to `configure', and exit.
-
-`--help=short'
-`--help=recursive'
- Print a summary of the options unique to this package's
- `configure', and exit. The `short' variant lists options used
- only in the top level, while the `recursive' variant lists options
- also present in any nested packages.
-
-`--version'
-`-V'
- Print the version of Autoconf used to generate the `configure'
- script, and exit.
-
-`--cache-file=FILE'
- Enable the cache: use and save the results of the tests in FILE,
- traditionally `config.cache'. FILE defaults to `/dev/null' to
- disable caching.
-
-`--config-cache'
-`-C'
- Alias for `--cache-file=config.cache'.
-
-`--quiet'
-`--silent'
-`-q'
- Do not print messages saying which checks are being made. To
- suppress all normal output, redirect it to `/dev/null' (any error
- messages will still be shown).
-
-`--srcdir=DIR'
- Look for the package's source code in directory DIR. Usually
- `configure' can determine that directory automatically.
-
-`--prefix=DIR'
- Use DIR as the installation prefix. *note Installation Names::
- for more details, including other options available for fine-tuning
- the installation locations.
-
-`--no-create'
-`-n'
- Run the configure checks, but stop before creating any output
- files.
-
-`configure' also accepts some other, not widely useful, options. Run
-`configure --help' for more details.
-
diff --git a/autoconf/Makefile.am b/autoconf/Makefile.am
deleted file mode 100644
index 1eaa560ff8..0000000000
--- a/autoconf/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-
-AM_CFLAGS = @BUILD_CFLAGS@
-lib_LTLIBRARIES = libsqlite3.la
-libsqlite3_la_SOURCES = sqlite3.c
-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
-
-bin_PROGRAMS = sqlite3
-sqlite3_SOURCES = shell.c sqlite3.h
-EXTRA_sqlite3_SOURCES = sqlite3.c
-sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
-sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
-sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_DQS=0 -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)
-
-include_HEADERS = sqlite3.h sqlite3ext.h
-
-EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
-pkgconfigdir = ${libdir}/pkgconfig
-pkgconfig_DATA = sqlite3.pc
-
-man_MANS = sqlite3.1
diff --git a/autoconf/Makefile.in b/autoconf/Makefile.in
new file mode 100644
index 0000000000..2f69082409
--- /dev/null
+++ b/autoconf/Makefile.in
@@ -0,0 +1,281 @@
+########################################################################
+# This is a main makefile for the "autoconf" bundle of SQLite. This is
+# a trimmed-down version of the canonical makefile, devoid of most
+# documentation. For the full docs, see /main.mk in the canonical
+# source tree.
+#
+# Maintenance reminders:
+#
+# - To keep this working with an out-of-tree build, be sure to prefix
+# input file names with $(TOP)/ where appropriate (which is most
+# places).
+#
+# - The original/canonical recipes can be found in /main.mk in the
+# canonical source tree.
+all:
+
+TOP = @abs_top_srcdir@
+
+PACKAGE_VERSION = @PACKAGE_VERSION@
+
+#
+# Filename extensions for binaries and libraries
+#
+B.exe = @BUILD_EXEEXT@
+T.exe = @TARGET_EXEEXT@
+B.dll = @BUILD_DLLEXT@
+T.dll = @TARGET_DLLEXT@
+B.lib = @BUILD_LIBEXT@
+T.lib = @TARGET_LIBEXT@
+
+#
+# Autotools-compatibility dirs
+#
+prefix = @prefix@
+datadir = @datadir@
+mandir = @mandir@
+includedir = @includedir@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+
+#
+# Required binaries
+#
+INSTALL = @BIN_INSTALL@
+AR = @AR@
+AR.flags = cr
+CC = @CC@
+
+
+ENABLE_LIB_SHARED = @ENABLE_LIB_SHARED@
+ENABLE_LIB_STATIC = @ENABLE_LIB_STATIC@
+
+CFLAGS = @CFLAGS@ @CPPFLAGS@
+#
+# $(LDFLAGS.configure) represents any LDFLAGS=... the client passes to
+# configure. See main.mk.
+#
+LDFLAGS.configure = @LDFLAGS@
+
+CFLAGS.core = @SH_CFLAGS@
+LDFLAGS.shlib = @SH_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+LDFLAGS.rpath = @LDFLAGS_RPATH@
+LDFLAGS.pthread = @LDFLAGS_PTHREAD@
+LDFLAGS.dlopen = @LDFLAGS_DLOPEN@
+LDFLAGS.readline = @LDFLAGS_READLINE@
+CFLAGS.readline = @CFLAGS_READLINE@
+LDFLAGS.rt = @LDFLAGS_RT@
+LDFLAGS.icu = @LDFLAGS_ICU@
+CFLAGS.icu = @CFLAGS_ICU@
+
+# When cross-compiling, we need to avoid the -s flag because it only
+# works on the build host's platform.
+INSTALL.strip.1 = $(INSTALL)
+INSTALL.strip.0 = $(INSTALL) -s
+INSTALL.strip = $(INSTALL.strip.@IS_CROSS_COMPILING@)
+INSTALL.noexec = $(INSTALL) -m 0644
+
+install-dir.bin = $(DESTDIR)$(bindir)
+install-dir.lib = $(DESTDIR)$(libdir)
+install-dir.include = $(DESTDIR)$(includedir)
+install-dir.pkgconfig = $(DESTDIR)$(libdir)/pkgconfig
+install-dir.man1 = $(DESTDIR)$(mandir)/man1
+install-dir.all = $(install-dir.bin) $(install-dir.include) \
+ $(install-dir.lib) $(install-dir.man1) \
+ $(install-dir.pkgconfig)
+$(install-dir.all):
+ @if [ ! -d "$@" ]; then set -x; $(INSTALL) -d "$@"; fi
+# ^^^^ on some platforms, install -d fails if the target already exists.
+
+
+#
+# Vars with the AS_ prefix are specifically related to AutoSetup.
+#
+# AS_AUTO_DEF is the main configure script.
+#
+AS_AUTO_DEF = $(TOP)/auto.def
+
+#
+# Shell commands to re-run $(TOP)/configure with the same args it was
+# invoked with to produce this makefile.
+#
+AS_AUTORECONFIG = @SQLITE_AUTORECONFIG@
+Makefile: $(TOP)/Makefile.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite3.pc: $(TOP)/sqlite3.pc.in $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+sqlite_cfg.h: $(AS_AUTO_DEF)
+ $(AS_AUTORECONFIG)
+ @touch $@
+
+#
+# CFLAGS for sqlite3$(T.exe)
+#
+SHELL_OPT ?= @OPT_SHELL@
+
+#
+# Library-level feature flags
+#
+OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@
+
+LDFLAGS.libsqlite3.soname = @LDFLAGS_LIBSQLITE3_SONAME@
+# soname: see https://sqlite.org/src/forumpost/5a3b44f510df8ded
+LDFLAGS.libsqlite3.os-specific = \
+ @LDFLAGS_MAC_CVERSION@ @LDFLAGS_MAC_INSTALL_NAME@ @LDFLAGS_OUT_IMPLIB@
+
+LDFLAGS.libsqlite3 = \
+ $(LDFLAGS.rpath) $(LDFLAGS.pthread) \
+ $(LDFLAGS.math) $(LDFLAGS.dlopen) \
+ $(LDFLAGS.zlib) $(LDFLAGS.icu) \
+ $(LDFLAGS.rt) $(LDFLAGS.configure)
+CFLAGS.libsqlite3 = -I. $(CFLAGS.core) $(CFLAGS.icu) $(OPT_FEATURE_FLAGS)
+
+sqlite3.o: $(TOP)/sqlite3.h $(TOP)/sqlite3.c
+ $(CC) -c $(TOP)/sqlite3.c -o $@ $(CFLAGS) $(CFLAGS.libsqlite3)
+
+libsqlite3.LIB = libsqlite3$(T.lib)
+libsqlite3.DLL.basename = @SQLITE_DLL_BASENAME@
+libsqlite3.out.implib = @SQLITE_OUT_IMPLIB@
+libsqlite3.DLL = $(libsqlite3.DLL.basename)$(T.dll)
+libsqlite3.DLL.install-rules = @SQLITE_DLL_INSTALL_RULES@
+
+$(libsqlite3.DLL): sqlite3.o
+ $(CC) -o $@ sqlite3.o $(LDFLAGS.shlib) \
+ $(LDFLAGS) $(LDFLAGS.libsqlite3) \
+ $(LDFLAGS.libsqlite3.os-specific) $(LDFLAGS.libsqlite3.soname)
+$(libsqlite3.DLL)-1: $(libsqlite3.DLL)
+$(libsqlite3.DLL)-0:
+all: $(libsqlite3.DLL)-$(ENABLE_LIB_SHARED)
+
+$(libsqlite3.LIB): sqlite3.o
+ $(AR) $(AR.flags) $@ sqlite3.o
+$(libsqlite3.LIB)-1: $(libsqlite3.LIB)
+$(libsqlite3.LIB)-0:
+all: $(libsqlite3.LIB)-$(ENABLE_LIB_STATIC)
+
+#
+# Maintenance reminder: the install-dll-... rules must be kept in sync
+# with the main copies rom /main.mk.
+#
+install-dll-out-implib: $(install-dir.lib) $(libsqlite3.DLL)
+ if [ x != "x$(libsqlite3.out.implib)" ] && [ -f "$(libsqlite3.out.implib)" ]; then \
+ $(INSTALL) $(libsqlite3.out.implib) "$(install-dir.lib)"; \
+ fi
+
+install-dll-unix-generic: install-dll-out-implib
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.lib)"
+ @echo "Setting up $(libsqlite3.DLL) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ rm -f $(libsqlite3.DLL).0 $(libsqlite3.DLL).$(PACKAGE_VERSION) || exit $$?; \
+ mv $(libsqlite3.DLL) $(libsqlite3.DLL).$(PACKAGE_VERSION) || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL) || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0 || exit $$?; \
+ ls -la $(libsqlite3.DLL) $(libsqlite3.DLL).[a03]*; \
+ if [ -e $(libsqlite3.DLL).0.8.6 ]; then \
+ echo "ACHTUNG: legacy libtool-compatible install found. Re-linking it..."; \
+ rm -f libsqlite3.la $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.DLL).0.8.6; \
+ elif [ x1 = "x$(INSTALL_SO_086_LINK)" ]; then \
+ echo "ACHTUNG: installing legacy libtool-style links because INSTALL_SO_086_LINK=1"; \
+ rm -f libsqlite3.la $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ln -s $(libsqlite3.DLL).$(PACKAGE_VERSION) $(libsqlite3.DLL).0.8.6 || exit $$?; \
+ ls -la $(libsqlite3.DLL).0.8.6; \
+ fi
+
+install-dll-msys: install-dll-out-implib $(install-dir.bin)
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.bin)"
+# ----------------------------------------------^^^ yes, bin
+install-dll-mingw: install-dll-msys
+install-dll-cygwin: install-dll-msys
+
+install-dll-darwin: $(install-dir.lib) $(libsqlite3.DLL)
+ $(INSTALL) $(libsqlite3.DLL) "$(install-dir.lib)"
+ @echo "Setting up $(libsqlite3.DLL) version symlinks..."; \
+ cd "$(install-dir.lib)" || exit $$?; \
+ rm -f libsqlite3.0$(T.dll) libsqlite3.$(PACKAGE_VERSION)$(T.dll) || exit $$?; \
+ dllname=libsqlite3.$(PACKAGE_VERSION)$(T.dll); \
+ mv $(libsqlite3.DLL) $$dllname || exit $$?; \
+ ln -s $$dllname $(libsqlite3.DLL) || exit $$?; \
+ ln -s $$dllname libsqlite3.0$(T.dll) || exit $$?; \
+ ls -la $$dllname $(libsqlite3.DLL) libsqlite3.0$(T.dll)
+
+install-dll-1: install-dll-$(libsqlite3.DLL.install-rules)
+install-dll-0 install-dll-:
+install-dll: install-dll-$(ENABLE_LIB_SHARED)
+install: install-dll
+
+install-lib-1: $(install-dir.lib) $(libsqlite3.LIB)
+ $(INSTALL.noexec) $(libsqlite3.LIB) "$(install-dir.lib)"
+install-lib-0 install-lib-:
+install-lib: install-lib-$(ENABLE_LIB_STATIC)
+install: install-lib
+
+
+# Flags to link the shell app either directly against sqlite3.c
+# (ENABLE_STATIC_SHELL==1) or libsqlite3.so (ENABLE_STATIC_SHELL==0).
+#
+ENABLE_STATIC_SHELL = @ENABLE_STATIC_SHELL@
+sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS.libsqlite3)
+sqlite3-shell-link-flags.0 = -L. -lsqlite3 $(LDFLAGS.zlib)
+sqlite3-shell-deps.1 = $(TOP)/sqlite3.c
+sqlite3-shell-deps.0 = $(libsqlite3.DLL)
+sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL))
+ $(CC) -o $@ \
+ $(TOP)/shell.c $(sqlite3-shell-link-flags.$(ENABLE_STATIC_SHELL)) \
+ -I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \
+ $(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
+ $(LDFLAGS) $(LDFLAGS.readline)
+
+all: sqlite3$(T.exe)
+
+install-shell: sqlite3$(T.exe) $(install-dir.bin)
+ $(INSTALL.strip) sqlite3$(T.exe) "$(install-dir.bin)"
+install: install-shell
+
+install-headers: $(TOP)/sqlite3.h $(install-dir.include)
+ $(INSTALL.noexec) $(TOP)/sqlite3.h $(TOP)/sqlite3ext.h "$(install-dir.include)"
+install: install-headers
+
+install-pc: sqlite3.pc $(install-dir.pkgconfig)
+ $(INSTALL.noexec) sqlite3.pc "$(install-dir.pkgconfig)"
+install: install-pc
+
+install-man1: $(TOP)/sqlite3.1 $(install-dir.man1)
+ $(INSTALL.noexec) $(TOP)/sqlite3.1 "$(install-dir.man1)"
+install: install-man1
+
+clean:
+ rm -f *.o sqlite3$(T.exe)
+ rm -f $(libsqlite3.LIB) $(libsqlite3.DLL) libsqlite3$(T.dll).a
+
+distclean: clean
+ rm -f jimsh0$(T.exe) config.* sqlite3.pc sqlite_cfg.h Makefile
+
+DIST_FILES := \
+ README.txt VERSION \
+ auto.def autosetup configure tea \
+ sqlite3.h sqlite3.c shell.c sqlite3ext.h \
+ Makefile.in Makefile.msc Makefile.fallback \
+ sqlite3.rc sqlite3rc.h Replace.cs \
+ sqlite3.pc.in sqlite3.1
+
+# Maintenance note: dist_name must be sqlite-$(PACKAGE_VERSION) so
+# that tool/mkautoconfamal.sh knows how to find it.
+dist_name = sqlite-$(PACKAGE_VERSION)
+dist_tarball = $(dist_name).tar.gz
+dist:
+ rm -fr $(dist_name)
+ mkdir -p $(dist_name)
+ cp -rp $(DIST_FILES) $(dist_name)/.
+ rm -f $(dist_name)/tea/configure.ac.in
+ tar czf $(dist_tarball) $(dist_name)
+ rm -fr $(dist_name)
+ ls -l $(dist_tarball)
diff --git a/autoconf/Makefile.msc b/autoconf/Makefile.msc
index 280bb95deb..47e0a83af8 100644
--- a/autoconf/Makefile.msc
+++ b/autoconf/Makefile.msc
@@ -18,6 +18,15 @@
TOP = .
+# Optionally set EXTRA_SRC to a list of C files to append to
+# the generated sqlite3.c. Any sqlite3 extensions added this
+# way may require manual editing, as described in
+# https://sqlite.org/forum/forumpost/903f721f3e7c0d25
+#
+!IFNDEF EXTRA_SRC
+EXTRA_SRC =
+!ENDIF
+
# Set this non-0 to enable full warnings (-W4, etc) when compiling.
#
!IFNDEF USE_FULLWARN
@@ -59,6 +68,14 @@ USE_STDCALL = 0
USE_SEH = 1
!ENDIF
+# Use STATICALLY_LINK_TCL=1 to statically link against TCL
+#
+!IFNDEF STATICALLY_LINK_TCL
+STATICALLY_LINK_TCL = 0
+!ELSEIF $(STATICALLY_LINK_TCL)!=0
+CCOPTS = $(CCOPTS) -DSTATIC_BUILD
+!ENDIF
+
# Set this non-0 to have the shell executable link against the core dynamic
# link library.
#
@@ -294,6 +311,7 @@ SQLITE3EXEPDB = /pdb:sqlite3sh.pdb
# the Windows platform.
#
!IFNDEF OPT_FEATURE_FLAGS
+OPT_FEATURE_FLAGS = $(OPT_XTRA)
!IF $(MINIMAL_AMALGAMATION)==0
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS5=1
@@ -307,6 +325,14 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
+# Additional feature-options above and beyond what are normally used can be
+# be added using OPTIONS=.... on the command-line. These values are
+# appended to the OPT_FEATURE_FLAGS variable.
+#
+!IFDEF OPTIONS
+OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) $(OPTIONS)
+!ENDIF
+
# Should the session extension be enabled? If so, add compilation options
# to enable it.
#
@@ -775,15 +801,6 @@ RCC = $(RCC) -DSQLITE_THREAD_OVERRIDE_LOCK=-1
TLIBS =
!ENDIF
-# Flags controlling use of the in memory btree implementation
-#
-# SQLITE_TEMP_STORE is 0 to force temporary tables to be in a file, 1 to
-# default to file, 2 to default to memory, and 3 to force temporary
-# tables to always be in memory.
-#
-TCC = $(TCC) -DSQLITE_TEMP_STORE=1
-RCC = $(RCC) -DSQLITE_TEMP_STORE=1
-
# Enable/disable loadable extensions, and other optional features
# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*).
# The same set of OMIT and ENABLE flags should be passed to the
@@ -990,6 +1007,7 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_STMT_SCANSTATUS=1
+SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF
@@ -1014,6 +1032,11 @@ dll: $(SQLITE3DLL)
#
shell: $(SQLITE3EXE)
+# jimsh0 - replacement for tclsh
+#
+jimsh0.exe: $(TOP)\autosetup\jimsh0.c
+ cl -DHAVE__FULLPATH=1 $(TOP)\autosetup\jimsh0.c
+
$(SQLITE3DLL): $(LIBOBJ) $(LIBRESOBJS) $(CORE_LINK_DEP)
$(LD) $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) /DLL $(CORE_LINK_OPTS) /OUT:$@ $(LIBOBJ) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
@@ -1064,5 +1087,6 @@ $(LIBRESOBJS): $(TOP)\sqlite3.rc rcver.vc $(SQLITE3H)
clean:
del /Q *.exp *.lo *.ilk *.lib *.obj *.ncb *.pdb *.sdf *.suo 2>NUL
- del /Q *.bsc *.def *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q *.bsc *.cod *.da *.bb *.bbg *.vc gmon.out 2>NUL
+ del /Q sqlite3.def tclsqlite3.def 2>NUL
del /Q $(SQLITE3EXE) $(SQLITE3DLL) Replace.exe 2>NUL
diff --git a/autoconf/README.first b/autoconf/README.first
index 5c2ea0a70f..75c4a76d61 100644
--- a/autoconf/README.first
+++ b/autoconf/README.first
@@ -1,11 +1,12 @@
-This directory contains components use to build an autoconf-ready package
-of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz
+This directory contains components used to build an autoconf-like
+package of the SQLite amalgamation: sqlite-autoconf-30XXXXXX.tar.gz
-To build the autoconf amalgamation, run from the top-level:
+To build the autoconf amalgamation, run from the top of the canonical
+source tree:
./configure
make amalgamation-tarball
-The amalgamation-tarball target (also available in "main.mk") runs the
-script tool/mkautoconfamal.sh which does the work. Refer to that script
-for details.
+The amalgamation-tarball target (available in "main.mk") runs the
+script tool/mkautoconfamal.sh which does the work. Refer to that
+script for details.
diff --git a/autoconf/README.txt b/autoconf/README.txt
index ccf5e235ac..646c0a1215 100644
--- a/autoconf/README.txt
+++ b/autoconf/README.txt
@@ -4,13 +4,44 @@ This package contains:
* the sqlite3.h and sqlite3ext.h header files that define the C-language
interface to the sqlite3.c library file
* the shell.c file used to build the sqlite3 command-line shell program
- * autoconf/automake installation infrastucture for building on POSIX
+ * autoconf-like installation infrastucture for building on POSIX
compliant systems
* a Makefile.msc, sqlite3.rc, and Replace.cs for building with Microsoft
Visual C++ on Windows
-SUMMARY OF HOW TO BUILD
-=======================
+WHY USE THIS PACKAGE?
+=====================
+
+The canonical make system for SQLite requires TCL as part of the build
+process. Various TCL scripts are used to generate parts of the code and
+TCL is used to run tests. But some people would prefer to build SQLite
+using only generic tools and without having to install TCL. The purpose
+of this package is to provide that capability.
+
+This package contains a pre-build SQLite amalgamation file "sqlite3.c"
+(and its associated header file "sqlite3.h"). Because the
+amalgamation has been pre-built, no TCL is required for the code
+generate (the configure script itself is written in TCL but it can use
+the embedded copy of JimTCL).
+
+REASONS TO USE THE CANONICAL BUILD SYSTEM RATHER THAN THIS PACKAGE
+==================================================================
+
+ * the cononical build system allows you to run tests to verify that
+ the build worked
+ * the canonical build system supports more compile-time options
+ * the canonical build system works for any arbitrary check-in to
+ the SQLite source tree
+
+Step-by-step instructions on how to build using the canonical make
+system for SQLite can be found at:
+
+ https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md
+ https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md
+
+
+SUMMARY OF HOW TO BUILD USING THIS PACKAGE
+==========================================
Unix: ./configure; make
Windows: nmake /f Makefile.msc
@@ -18,14 +49,12 @@ SUMMARY OF HOW TO BUILD
BUILDING ON POSIX
=================
-The generic installation instructions for autoconf/automake are found
-in the INSTALL file.
-
-The following SQLite specific boolean options are supported:
+The configure script follows common conventions, making it easy
+to use for anyone who has configured a software tree before.
+It supports a number of build-time flags, the full list of which
+can be seen by running:
- --enable-readline use readline in shell tool [default=yes]
- --enable-threadsafe build a thread-safe library [default=yes]
- --enable-dynamic-extensions support loadable extensions [default=yes]
+ ./configure --help
The default value for the CFLAGS variable (options passed to the C
compiler) includes debugging symbols in the build, resulting in larger
@@ -36,10 +65,11 @@ line like this:
to produce a smaller installation footprint.
-Other SQLite compilation parameters can also be set using CFLAGS. For
+Many SQLite compilation parameters can be defined by passing flags
+to the configure script. Others may be passed on in the CFLAGS. For
example:
- $ CFLAGS="-Os -DSQLITE_THREADSAFE=0" ./configure
+ $ CFLAGS="-Os -DSQLITE_OMIT_DEPRECATED" ./configure
BUILDING WITH MICROSOFT VISUAL C++
@@ -53,48 +83,6 @@ Using Microsoft Visual C++ 2005 (or later) is recommended. Several Windows
platform variants may be built by adding additional macros to the NMAKE
command line.
-Building for WinRT 8.0
-----------------------
-
- FOR_WINRT=1
-
-Using Microsoft Visual C++ 2012 (or later) is required. When using the
-above, something like the following macro will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\8.0\lib\win8\um\x86"
-
-Building for WinRT 8.1
-----------------------
-
- FOR_WINRT=1
-
-Using Microsoft Visual C++ 2013 (or later) is required. When using the
-above, something like the following macro will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\8.1\lib\winv6.3\um\x86"
-
-Building for UWP 10.0
----------------------
-
- FOR_WINRT=1 FOR_UWP=1
-
-Using Microsoft Visual C++ 2015 (or later) is required. When using the
-above, something like the following macros will need to be added to the
-NMAKE command line as well:
-
- "NSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86"
- "PSDKLIBPATH=%WindowsSdkDir%\..\10\lib\10.0.10586.0\um\x86"
- "NUCRTLIBPATH=%UniversalCRTSdkDir%\..\10\lib\10.0.10586.0\ucrt\x86"
-
-Building for the Windows 10 SDK
--------------------------------
-
- FOR_WIN10=1
-
-Using Microsoft Visual C++ 2015 (or later) is required. When using the
-above, no other macros should be needed on the NMAKE command line.
Other preprocessor defines
--------------------------
diff --git a/autoconf/auto.def b/autoconf/auto.def
new file mode 100644
index 0000000000..3ba900d957
--- /dev/null
+++ b/autoconf/auto.def
@@ -0,0 +1,10 @@
+#!/do/not/tclsh
+# ^^^ help out editors which guess this file's content type.
+#
+# This is the main autosetup-compatible configure script for the
+# "autoconf" bundle of the SQLite project.
+use sqlite-config
+sqlite-configure autoconf {
+ sqlite-check-common-bins
+ sqlite-check-common-system-deps
+}
diff --git a/autoconf/configure.ac b/autoconf/configure.ac
deleted file mode 100644
index 0c7a32db1f..0000000000
--- a/autoconf/configure.ac
+++ /dev/null
@@ -1,270 +0,0 @@
-
-#-----------------------------------------------------------------------
-# Supports the following non-standard switches.
-#
-# --enable-threadsafe
-# --enable-readline
-# --enable-editline
-# --enable-static-shell
-# --enable-dynamic-extensions
-#
-
-AC_PREREQ(2.61)
-AC_INIT(sqlite, --SQLITE-VERSION--, http://www.sqlite.org)
-AC_CONFIG_SRCDIR([sqlite3.c])
-AC_CONFIG_AUX_DIR([.])
-
-# Use automake.
-AM_INIT_AUTOMAKE([foreign])
-
-AC_SYS_LARGEFILE
-
-# Check for required programs.
-AC_PROG_CC
-AC_PROG_LIBTOOL
-AC_PROG_MKDIR_P
-
-# Check for library functions that SQLite can optionally use.
-AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
-AC_FUNC_STRERROR_R
-
-AC_CONFIG_FILES([Makefile sqlite3.pc])
-BUILD_CFLAGS=
-AC_SUBST(BUILD_CFLAGS)
-
-#-------------------------------------------------------------------------
-# Two options to enable readline compatible libraries:
-#
-# --enable-editline
-# --enable-readline
-#
-# Both are enabled by default. If, after command line processing both are
-# still enabled, the script searches for editline first and automatically
-# disables readline if it is found. So, to use readline explicitly, the
-# user must pass "--disable-editline". To disable command line editing
-# support altogether, "--disable-editline --disable-readline".
-#
-# When searching for either library, check for headers before libraries
-# as some distros supply packages that contain libraries but not header
-# files, which come as a separate development package.
-#
-AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])])
-AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])])
-
-AS_IF([ test x"$enable_editline" != xno ],[
- AC_CHECK_HEADERS([editline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS([readline],[edit],[
- AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline)
- READLINE_LIBS="$LIBS -ltinfo"
- enable_readline=no
- ],[],[-ltinfo])
- AS_UNSET(ac_cv_search_readline)
- LIBS=$sLIBS
- ])
-])
-
-AS_IF([ test x"$enable_readline" != xno ],[
- AC_CHECK_HEADERS([readline/readline.h],[
- sLIBS=$LIBS
- LIBS=""
- AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], [])
- AC_SEARCH_LIBS(readline,[readline edit], [
- AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper)
- READLINE_LIBS=$LIBS
- ])
- LIBS=$sLIBS
- ])
-])
-
-AC_SUBST(READLINE_LIBS)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-threadsafe
-#
-AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
- [--enable-threadsafe], [build a thread-safe library [default=yes]])],
- [], [enable_threadsafe=yes])
-if test x"$enable_threadsafe" == "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
- AC_SEARCH_LIBS(pthread_create, pthread)
- AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-dynamic-extensions
-#
-AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING(
- [--enable-dynamic-extensions], [support loadable extensions [default=yes]])],
- [], [enable_dynamic_extensions=yes])
-if test x"$enable_dynamic_extensions" != "xno"; then
- AC_SEARCH_LIBS(dlopen, dl)
-else
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-AC_MSG_CHECKING([for whether to support dynamic extensions])
-AC_MSG_RESULT($enable_dynamic_extensions)
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-math
-#
-AC_ARG_ENABLE(math, [AS_HELP_STRING(
- [--enable-math], [SQL math functions [default=yes]])],
- [], [enable_math=yes])
-AC_MSG_CHECKING([SQL math functions])
-if test x"$enable_math" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(ceil, m)
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts4
-#
-AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
- [--enable-fts4], [include fts4 support [default=yes]])],
- [], [enable_fts4=yes])
-AC_MSG_CHECKING([FTS4 extension])
-if test x"$enable_fts4" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts3
-#
-AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
- [--enable-fts3], [include fts3 support [default=no]])],
- [], [])
-AC_MSG_CHECKING([FTS3 extension])
-if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-fts5
-#
-AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
- [--enable-fts5], [include fts5 support [default=yes]])],
- [], [enable_fts5=yes])
-AC_MSG_CHECKING([FTS5 extension])
-if test x"$enable_fts5" = "xyes"; then
- AC_MSG_RESULT([enabled])
- AC_SEARCH_LIBS(log, m)
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-rtree
-#
-AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
- [--enable-rtree], [include rtree support [default=yes]])],
- [], [enable_rtree=yes])
-AC_MSG_CHECKING([RTREE extension])
-if test x"$enable_rtree" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-session
-#
-AC_ARG_ENABLE(session, [AS_HELP_STRING(
- [--enable-session], [enable the session extension [default=no]])],
- [], [])
-AC_MSG_CHECKING([Session extension])
-if test x"$enable_session" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
- AC_MSG_RESULT([enabled])
-else
- AC_MSG_RESULT([disabled])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-debug
-#
-AC_ARG_ENABLE(debug, [AS_HELP_STRING(
- [--enable-debug], [build with debugging features enabled [default=no]])],
- [], [])
-AC_MSG_CHECKING([Build type])
-if test x"$enable_debug" = "xyes"; then
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
- CFLAGS="-g -O0"
- AC_MSG_RESULT([debug])
-else
- AC_MSG_RESULT([release])
-fi
-#-----------------------------------------------------------------------
-
-#-----------------------------------------------------------------------
-# --enable-static-shell
-#
-AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
- [--enable-static-shell],
- [statically link libsqlite3 into shell tool [default=yes]])],
- [], [enable_static_shell=yes])
-if test x"$enable_static_shell" = "xyes"; then
- EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
-else
- EXTRA_SHELL_OBJ=libsqlite3.la
-fi
-AC_SUBST(EXTRA_SHELL_OBJ)
-#-----------------------------------------------------------------------
-
-AC_CHECK_FUNCS(posix_fallocate)
-AC_CHECK_HEADERS(zlib.h,[
- AC_SEARCH_LIBS(deflate,z,[BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"])
-])
-
-AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"])
-AC_SUBST(SHELL_CFLAGS)
-
-#-----------------------------------------------------------------------
-# UPDATE: Maybe it's better if users just set CFLAGS before invoking
-# configure. This option doesn't really add much...
-#
-# --enable-tempstore
-#
-# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
-# [--enable-tempstore],
-# [in-memory temporary tables (never, no, yes, always) [default=no]])],
-# [], [enable_tempstore=no])
-# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
-# case "$enable_tempstore" in
-# never ) TEMP_STORE=0 ;;
-# no ) TEMP_STORE=1 ;;
-# always ) TEMP_STORE=3 ;;
-# yes ) TEMP_STORE=3 ;;
-# * )
-# TEMP_STORE=1
-# enable_tempstore=yes
-# ;;
-# esac
-# AC_MSG_RESULT($enable_tempstore)
-# AC_SUBST(TEMP_STORE)
-#-----------------------------------------------------------------------
-
-AC_OUTPUT
diff --git a/autoconf/tea/Makefile.in b/autoconf/tea/Makefile.in
index 5264f89f3c..cc98ab1825 100644
--- a/autoconf/tea/Makefile.in
+++ b/autoconf/tea/Makefile.in
@@ -99,7 +99,6 @@ INSTALL_LIBRARY = @INSTALL_LIBRARY@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
CC = @CC@
-CCLD = @CCLD@
CFLAGS_DEFAULT = @CFLAGS_DEFAULT@
CFLAGS_WARNING = @CFLAGS_WARNING@
EXEEXT = @EXEEXT@
@@ -311,19 +310,6 @@ VPATH = $(srcdir):$(srcdir)/generic:$(srcdir)/unix:$(srcdir)/win:$(srcdir)/macos
.c.@OBJEXT@:
$(COMPILE) -c `@CYGPATH@ $<` -o $@
-tclsample.@OBJEXT@: sampleUuid.h
-
-$(srcdir)/manifest.uuid:
- printf "git-" >$(srcdir)/manifest.uuid
- (cd $(srcdir); git rev-parse HEAD >>$(srcdir)/manifest.uuid || \
- (printf "svn-r" >$(srcdir)/manifest.uuid ; \
- svn info --show-item last-changed-revision >>$(srcdir)/manifest.uuid) || \
- printf "unknown" >$(srcdir)/manifest.uuid)
-
-sampleUuid.h: $(srcdir)/manifest.uuid
- echo "#define SAMPLE_VERSION_UUID \\" >$@
- cat $(srcdir)/manifest.uuid >>$@
- echo "" >>$@
#========================================================================
# Distribution creation
@@ -451,6 +437,8 @@ install-bin-binaries: binaries
fi; \
done
+.SUFFIXES: .c .$(OBJEXT)
+
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) \
&& CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
diff --git a/autoconf/tea/README b/autoconf/tea/README
deleted file mode 100644
index 99dc8b8f03..0000000000
--- a/autoconf/tea/README
+++ /dev/null
@@ -1,36 +0,0 @@
-This is the SQLite extension for Tcl using the Tcl Extension
-Architecture (TEA). For additional information on SQLite see
-
- http://www.sqlite.org/
-
-
-UNIX BUILD
-==========
-
-Building under most UNIX systems is easy, just run the configure script
-and then run make. For more information about the build process, see
-the tcl/unix/README file in the Tcl src dist. The following minimal
-example will install the extension in the /opt/tcl directory.
-
- $ cd sqlite-*-tea
- $ ./configure --prefix=/opt/tcl
- $ make
- $ make install
-
-WINDOWS BUILD
-=============
-
-The recommended method to build extensions under windows is to use the
-Msys + Mingw build process. This provides a Unix-style build while
-generating native Windows binaries. Using the Msys + Mingw build tools
-means that you can use the same configure script as per the Unix build
-to create a Makefile. See the tcl/win/README file for the URL of
-the Msys + Mingw download.
-
-If you have VC++ then you may wish to use the files in the win
-subdirectory and build the extension using just VC++. These files have
-been designed to be as generic as possible but will require some
-additional maintenance by the project developer to synchronise with
-the TEA configure.in and Makefile.in files. Instructions for using the
-VC++ makefile are written in the first part of the Makefile.vc
-file.
diff --git a/autoconf/tea/README.txt b/autoconf/tea/README.txt
new file mode 100644
index 0000000000..b50d4f29a8
--- /dev/null
+++ b/autoconf/tea/README.txt
@@ -0,0 +1,78 @@
+This is the SQLite extension for Tcl using the Tcl Extension
+Architecture (TEA).
+
+----------------------- A BETTER WAY ---------------------------
+
+A better way to build the TCL extension for SQLite is to use the
+canonical source code tarball. For Unix:
+
+ ./configure --with-tclsh=$(TCLSH)
+ make tclextension-install
+
+For Windows:
+
+ nmake /f Makefile.msc tclextension-install TCLSH_CMD=$(TCLSH)
+
+In both of the above, replace $(TCLSH) with the full pathname of
+of the tclsh that you want the SQLite extension to work with. See
+step-by-step instructions at the links below for more information:
+
+ https://sqlite.org/src/doc/trunk/doc/compile-for-unix.md
+ https://sqlite.org/src/doc/trunk/doc/compile-for-windows.md
+
+The whole point of the amalgamation-autoconf tarball (in which this
+README.txt file is embedded) is to provide a means of compiling
+SQLite that does not require first installing TCL and/or "tclsh".
+The canonical Makefile in the SQLite source tree provides more
+capabilities (such as the the ability to run test cases to ensure
+that the build worked) and is better maintained. The only
+downside of the canonical Makfile is that it requires a TCL
+installation. But if you are wanting to build the TCL extension for
+SQLite, then presumably you already have a TCL installation. So why
+not just use the more-capable and better-maintained canoncal Makefile?
+
+This TEA builder is derived from code found at
+
+ http://core.tcl-lang.org/tclconfig
+ http://core.tcl-lang.org/sampleextension
+
+The SQLite developers do not understand how it works. It seems to
+work for us. It might also work for you. But we cannot promise that.
+
+If you want to use this TEA builder and it works for you, that's fine.
+But if you have trouble, the first thing you should do is go back
+to using the canonical Makefile in the SQLite source tree.
+
+------------------------------------------------------------------
+
+
+UNIX BUILD
+==========
+
+Building under most UNIX systems is easy, just run the configure script
+and then run make. For more information about the build process, see
+the tcl/unix/README file in the Tcl src dist. The following minimal
+example will install the extension in the /opt/tcl directory.
+
+ $ cd sqlite-*-tea
+ $ ./configure --prefix=/opt/tcl
+ $ make
+ $ make install
+
+WINDOWS BUILD
+=============
+
+The recommended method to build extensions under windows is to use the
+Msys + Mingw build process. This provides a Unix-style build while
+generating native Windows binaries. Using the Msys + Mingw build tools
+means that you can use the same configure script as per the Unix build
+to create a Makefile. See the tcl/win/README file for the URL of
+the Msys + Mingw download.
+
+If you have VC++ then you may wish to use the files in the win
+subdirectory and build the extension using just VC++. These files have
+been designed to be as generic as possible but will require some
+additional maintenance by the project developer to synchronise with
+the TEA configure.in and Makefile.in files. Instructions for using the
+VC++ makefile are written in the first part of the Makefile.vc
+file.
diff --git a/autoconf/tea/configure.ac b/autoconf/tea/configure.ac.in
similarity index 99%
rename from autoconf/tea/configure.ac
rename to autoconf/tea/configure.ac.in
index 503494b37d..a13a1e7615 100644
--- a/autoconf/tea/configure.ac
+++ b/autoconf/tea/configure.ac.in
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
# so that we create the export library with the dll.
#-----------------------------------------------------------------------
-AC_INIT([sqlite],[3.44.2])
+AC_INIT([sqlite],[@VERSION@])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
@@ -97,7 +97,7 @@ TEA_ADD_TCL_SOURCES([])
# Patchs from rmax.
#--------------------------------------------------------------------
AC_ARG_WITH([system-sqlite],
- [AC_HELP_STRING([--with-system-sqlite],
+ [AS_HELP_STRING([--with-system-sqlite],
[use a system-supplied libsqlite3 instead of the bundled one])],
[], [with_system_sqlite=no])
if test x$with_system_sqlite != xno; then
diff --git a/autoconf/tea/pkgIndex.tcl.in b/autoconf/tea/pkgIndex.tcl.in
index f95f7d3893..666812dee7 100644
--- a/autoconf/tea/pkgIndex.tcl.in
+++ b/autoconf/tea/pkgIndex.tcl.in
@@ -3,8 +3,8 @@
#
if {[package vsatisfies [package provide Tcl] 9.0-]} {
package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE9@] sqlite3]
+ [list load [file join $dir @PKG_LIB_FILE9@] Sqlite3]
} else {
package ifneeded sqlite3 @PACKAGE_VERSION@ \
- [list load [file join $dir @PKG_LIB_FILE8@] sqlite3]
+ [list load [file join $dir @PKG_LIB_FILE8@] Sqlite3]
}
diff --git a/autoconf/tea/tclconfig/install-sh b/autoconf/tea/tclconfig/install-sh
index 7c34c3f926..ec298b5374 100644
--- a/autoconf/tea/tclconfig/install-sh
+++ b/autoconf/tea/tclconfig/install-sh
@@ -1,7 +1,7 @@
#!/bin/sh
# install - install a program, script, or datafile
-scriptversion=2011-04-20.01; # UTC
+scriptversion=2020-11-14.01; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
@@ -35,25 +35,21 @@ scriptversion=2011-04-20.01; # UTC
# 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
+# '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=" "" $nl"
+IFS=" $tab$nl"
-# set DOITPROG to echo to test this script
+# Set DOITPROG to "echo" to test this script.
-# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
-if test -z "$doit"; then
- doit_exec=exec
-else
- doit_exec=$doit
-fi
+doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
@@ -68,22 +64,16 @@ mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
-posix_glob='?'
-initialize_posix_glob='
- test "$posix_glob" != "?" || {
- if (set -f) 2>/dev/null; then
- posix_glob=
- else
- posix_glob=:
- fi
- }
-'
-
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
+
+backupsuffix=
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
@@ -97,7 +87,7 @@ dir_arg=
dst_arg=
copy_on_change=false
-no_target_directory=
+is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
@@ -114,19 +104,28 @@ Options:
--version display version info and exit.
-c (ignored)
- -C install only if different (preserve the last data modification time)
+ -C install only if different (preserve 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.
+ -p pass -p to $cpprog.
-s $stripprog installed files.
- -S $stripprog installed files.
+ -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
-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
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+If -S is not specified, no backups are attempted.
+
+Email bug reports to bug-automake@gnu.org.
+Automake home page: https://www.gnu.org/software/automake/
"
while test $# -ne 0; do
@@ -138,45 +137,62 @@ while test $# -ne 0; do
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
- shift;;
+ shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
- case $mode in
- *' '* | *' '* | *'
-'* | *'*'* | *'?'* | *'['*)
- echo "$0: invalid mode: $mode" >&2
- exit 1;;
- esac
- shift;;
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
-o) chowncmd="$chownprog $2"
- shift;;
+ shift;;
+
+ -p) cpprog="$cpprog -p";;
-s) stripcmd=$stripprog;;
- -S) stripcmd="$stripprog $2"
- shift;;
+ -S) backupsuffix="$2"
+ shift;;
- -t) dst_arg=$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) no_target_directory=true;;
+ -T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
- --) shift
- break;;
+ --) shift
+ break;;
- -*) echo "$0: invalid option: $1" >&2
- exit 1;;
+ -*) 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.
@@ -190,6 +206,10 @@ if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
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
@@ -198,11 +218,20 @@ if test $# -eq 0; then
echo "$0: no input file specified." >&2
exit 1
fi
- # It's OK to call `install-sh -d' without argument.
+ # 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
@@ -219,16 +248,16 @@ if test -z "$dir_arg"; then
*[0-7])
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw='% 200'
+ u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
- u_plus_rw=
+ u_plus_rw=
else
- u_plus_rw=,u+rw
+ u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
@@ -236,9 +265,9 @@ fi
for src
do
- # Protect names starting with `-'.
+ # Protect names problematic for 'test' and other utilities.
case $src in
- -*) src=./$src;;
+ -* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
@@ -246,6 +275,10 @@ do
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
+ # Don't chown directories that already exist.
+ if test $dstdir_status = 0; then
+ chowncmd=""
+ fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@@ -260,185 +293,150 @@ do
echo "$0: no destination specified." >&2
exit 1
fi
-
dst=$dst_arg
- # Protect names starting with `-'.
- case $dst in
- -*) dst=./$dst;;
- esac
- # If destination is a directory, append the input filename; won't work
- # if double slashes aren't ignored.
+ # If destination is a directory, append the input filename.
if test -d "$dst"; then
- if test -n "$no_target_directory"; then
- echo "$0: $dst_arg: Is a directory" >&2
- exit 1
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
fi
dstdir=$dst
- dst=$dstdir/`basename "$src"`
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
dstdir_status=0
else
- # Prefer dirname, but fall back on a substitute if dirname fails.
- dstdir=`
- (dirname "$dst") 2>/dev/null ||
- expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$dst" : 'X\(//\)[^/]' \| \
- X"$dst" : 'X\(//\)$' \| \
- X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
- echo X"$dst" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'
- `
-
+ 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
'')
- # Create intermediate dirs using mode 755 as modified by the umask.
- # This is like FreeBSD 'install' as of 1997-10-28.
- umask=`umask`
- case $stripcmd.$umask in
- # Optimize common cases.
- *[2367][2367]) mkdir_umask=$umask;;
- .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
- *[0-7])
- mkdir_umask=`expr $umask + 22 \
- - $umask % 100 % 40 + $umask % 20 \
- - $umask % 10 % 4 + $umask % 2
- `;;
- *) mkdir_umask=$umask,go-w;;
- esac
-
- # 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
+ # 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
- mkdir_mode=
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
-
- posix_mkdir=false
- case $umask in
- *[123567][0-7][0-7])
- # POSIX mkdir -p sets u+wx bits regardless of umask, which
- # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
- ;;
- *)
- tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
- trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
-
- if (umask $mkdir_umask &&
- exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/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-writeable bit of parent directory when it shouldn't.
- # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
- ls_ld_tmpdir=`ls -ld "$tmpdir"`
- case $ls_ld_tmpdir in
- d????-?r-*) different_mode=700;;
- d????-?--*) different_mode=755;;
- *) false;;
- esac &&
- $mkdirprog -m$different_mode -p -- "$tmpdir" && {
- ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
- test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
- }
- }
- then posix_mkdir=:
- fi
- rmdir "$tmpdir/d" "$tmpdir"
- else
- # Remove any dirs left behind by ancient mkdir implementations.
- rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
- fi
- trap '' 0;;
- esac;;
+ trap '' 0;;
esac
if
$posix_mkdir && (
- umask $mkdir_umask &&
- $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
- # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # 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='';;
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
esac
- eval "$initialize_posix_glob"
-
oIFS=$IFS
IFS=/
- $posix_glob set -f
+ set -f
set fnord $dstdir
shift
- $posix_glob set +f
+ set +f
IFS=$oIFS
prefixes=
for d
do
- test -z "$d" && 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/
+ 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
+ # 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
@@ -451,14 +449,25 @@ do
else
# Make a couple of temp file names in the proper directory.
- dsttmp=$dstdir/_inst.$$_
- rmtmp=$dstdir/_rm.$$_
+ 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 && $doit_exec $cpprog "$src" "$dsttmp") &&
+ (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.
#
@@ -473,20 +482,24 @@ do
# 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` &&
-
- eval "$initialize_posix_glob" &&
- $posix_glob set -f &&
+ 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 &&
- $posix_glob set +f &&
-
+ set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
+ # If $backupsuffix is set, and the file being installed
+ # already exists, attempt a backup. Don't worry if it fails,
+ # e.g., if mv doesn't support -f.
+ if test -n "$backupsuffix" && test -f "$dst"; then
+ $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+ fi
+
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
@@ -494,24 +507,24 @@ do
# 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"
+ # 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 "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd "$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
@@ -520,9 +533,9 @@ do
done
# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
+# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/autoconf/tea/tclconfig/tcl.m4 b/autoconf/tea/tclconfig/tcl.m4
index c83d660e18..237d50a7bd 100644
--- a/autoconf/tea/tclconfig/tcl.m4
+++ b/autoconf/tea/tclconfig/tcl.m4
@@ -53,6 +53,10 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
AS_HELP_STRING([--with-tcl],
[directory containing tcl configuration (tclConfig.sh)]),
[with_tclconfig="${withval}"])
+ AC_ARG_WITH(tcl8,
+ AS_HELP_STRING([--with-tcl8],
+ [Compile for Tcl8 in Tcl9 environment]),
+ [with_tcl8="${withval}"])
AC_MSG_CHECKING([for Tcl configuration])
AC_CACHE_VAL(ac_cv_c_tclconfig,[
@@ -138,10 +142,16 @@ AC_DEFUN([TEA_PATH_TCLCONFIG], [
`ls -d /usr/pkg/lib 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
+ `ls -d /usr/lib/tcl9.0 2>/dev/null` \
+ `ls -d /usr/lib/tcl8.7 2>/dev/null` \
`ls -d /usr/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl9.0 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl8.7 2>/dev/null` \
`ls -d /usr/local/lib/tcl8.6 2>/dev/null` \
`ls -d /usr/local/lib/tcl8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl9.0 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tcl8.7 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tcl8.6 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tcl8.5 2>/dev/null` \
; do
@@ -282,12 +292,18 @@ AC_DEFUN([TEA_PATH_TKCONFIG], [
`ls -d /usr/local/lib 2>/dev/null` \
`ls -d /usr/contrib/lib 2>/dev/null` \
`ls -d /usr/pkg/lib 2>/dev/null` \
+ `ls -d /usr/lib/tk9.0 2>/dev/null` \
+ `ls -d /usr/lib/tk8.7 2>/dev/null` \
`ls -d /usr/lib/tk8.6 2>/dev/null` \
`ls -d /usr/lib/tk8.5 2>/dev/null` \
`ls -d /usr/lib 2>/dev/null` \
`ls -d /usr/lib64 2>/dev/null` \
+ `ls -d /usr/local/lib/tk9.0 2>/dev/null` \
+ `ls -d /usr/local/lib/tk8.7 2>/dev/null` \
`ls -d /usr/local/lib/tk8.6 2>/dev/null` \
`ls -d /usr/local/lib/tk8.5 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk9.0 2>/dev/null` \
+ `ls -d /usr/local/lib/tcl/tk8.7 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tk8.6 2>/dev/null` \
`ls -d /usr/local/lib/tcl/tk8.5 2>/dev/null` \
; do
@@ -366,10 +382,10 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
AC_MSG_CHECKING([for existence of ${TCL_BIN_DIR}/tclConfig.sh])
if test -f "${TCL_BIN_DIR}/tclConfig.sh" ; then
- AC_MSG_RESULT([loading])
+ AC_MSG_RESULT([loading])
. "${TCL_BIN_DIR}/tclConfig.sh"
else
- AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh])
+ AC_MSG_RESULT([could not find ${TCL_BIN_DIR}/tclConfig.sh])
fi
# If the TCL_BIN_DIR is the build directory (not the install directory),
@@ -379,9 +395,9 @@ AC_DEFUN([TEA_LOAD_TCLCONFIG], [
# instead of TCL_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
if test -f "${TCL_BIN_DIR}/Makefile" ; then
- TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
- TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
- TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
+ TCL_LIB_SPEC="${TCL_BUILD_LIB_SPEC}"
+ TCL_STUB_LIB_SPEC="${TCL_BUILD_STUB_LIB_SPEC}"
+ TCL_STUB_LIB_PATH="${TCL_BUILD_STUB_LIB_PATH}"
elif test "`uname -s`" = "Darwin"; then
# If Tcl was built as a framework, attempt to use the libraries
# from the framework at the given location so that linking works
@@ -474,10 +490,10 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh])
if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then
- AC_MSG_RESULT([loading])
+ AC_MSG_RESULT([loading])
. "${TK_BIN_DIR}/tkConfig.sh"
else
- AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh])
+ AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh])
fi
# If the TK_BIN_DIR is the build directory (not the install directory),
@@ -487,9 +503,9 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
# instead of TK_BUILD_LIB_SPEC since it will work with both an
# installed and uninstalled version of Tcl.
if test -f "${TK_BIN_DIR}/Makefile" ; then
- TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}"
- TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}"
- TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}"
+ TK_LIB_SPEC="${TK_BUILD_LIB_SPEC}"
+ TK_STUB_LIB_SPEC="${TK_BUILD_STUB_LIB_SPEC}"
+ TK_STUB_LIB_PATH="${TK_BUILD_STUB_LIB_PATH}"
elif test "`uname -s`" = "Darwin"; then
# If Tk was built as a framework, attempt to use the libraries
# from the framework at the given location so that linking works
@@ -567,37 +583,37 @@ AC_DEFUN([TEA_LOAD_TKCONFIG], [
AC_DEFUN([TEA_PROG_TCLSH], [
AC_MSG_CHECKING([for tclsh])
if test -f "${TCL_BIN_DIR}/Makefile" ; then
- # tclConfig.sh is in Tcl build directory
- if test "${TEA_PLATFORM}" = "windows"; then
- if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
- elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
- fi
- else
- TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
- fi
+ # tclConfig.sh is in Tcl build directory
+ if test "${TEA_PLATFORM}" = "windows"; then
+ if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}s${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}t${EXEEXT}"
+ elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}" ; then
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}st${EXEEXT}"
+ fi
+ else
+ TCLSH_PROG="${TCL_BIN_DIR}/tclsh"
+ fi
else
- # tclConfig.sh is in install location
- if test "${TEA_PLATFORM}" = "windows"; then
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
- else
- TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
- fi
- list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
- `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
- `ls -d ${TCL_PREFIX}/bin 2>/dev/null`"
- for i in $list ; do
- if test -f "$i/${TCLSH_PROG}" ; then
- REAL_TCL_BIN_DIR="`cd "$i"; pwd`/"
- break
- fi
- done
- TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}"
+ # tclConfig.sh is in install location
+ if test "${TEA_PLATFORM}" = "windows"; then
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${EXEEXT}"
+ else
+ TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}"
+ fi
+ list="`ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null` \
+ `ls -d ${TCL_BIN_DIR}/.. 2>/dev/null` \
+ `ls -d ${TCL_PREFIX}/bin 2>/dev/null`"
+ for i in $list ; do
+ if test -f "$i/${TCLSH_PROG}" ; then
+ REAL_TCL_BIN_DIR="`cd "$i"; pwd`/"
+ break
+ fi
+ done
+ TCLSH_PROG="${REAL_TCL_BIN_DIR}${TCLSH_PROG}"
fi
AC_MSG_RESULT([${TCLSH_PROG}])
AC_SUBST(TCLSH_PROG)
@@ -625,37 +641,37 @@ AC_DEFUN([TEA_PROG_TCLSH], [
AC_DEFUN([TEA_PROG_WISH], [
AC_MSG_CHECKING([for wish])
if test -f "${TK_BIN_DIR}/Makefile" ; then
- # tkConfig.sh is in Tk build directory
- if test "${TEA_PLATFORM}" = "windows"; then
- if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}"
- elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then
- WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}"
- fi
- else
- WISH_PROG="${TK_BIN_DIR}/wish"
- fi
+ # tkConfig.sh is in Tk build directory
+ if test "${TEA_PLATFORM}" = "windows"; then
+ if test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}s${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}$s{EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}t${EXEEXT}"
+ elif test -f "${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}" ; then
+ WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}st${EXEEXT}"
+ fi
+ else
+ WISH_PROG="${TK_BIN_DIR}/wish"
+ fi
else
- # tkConfig.sh is in install location
- if test "${TEA_PLATFORM}" = "windows"; then
- WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
- else
- WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}"
- fi
- list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \
- `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \
- `ls -d ${TK_PREFIX}/bin 2>/dev/null`"
- for i in $list ; do
- if test -f "$i/${WISH_PROG}" ; then
- REAL_TK_BIN_DIR="`cd "$i"; pwd`/"
- break
- fi
- done
- WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}"
+ # tkConfig.sh is in install location
+ if test "${TEA_PLATFORM}" = "windows"; then
+ WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${EXEEXT}"
+ else
+ WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}"
+ fi
+ list="`ls -d ${TK_BIN_DIR}/../bin 2>/dev/null` \
+ `ls -d ${TK_BIN_DIR}/.. 2>/dev/null` \
+ `ls -d ${TK_PREFIX}/bin 2>/dev/null`"
+ for i in $list ; do
+ if test -f "$i/${WISH_PROG}" ; then
+ REAL_TK_BIN_DIR="`cd "$i"; pwd`/"
+ break
+ fi
+ done
+ WISH_PROG="${REAL_TK_BIN_DIR}${WISH_PROG}"
fi
AC_MSG_RESULT([${WISH_PROG}])
AC_SUBST(WISH_PROG)
@@ -717,22 +733,22 @@ AC_DEFUN([TEA_ENABLE_SHARED], [
if test "$shared_ok" = "yes" ; then
AC_MSG_RESULT([shared])
SHARED_BUILD=1
- STUBS_BUILD=1
+ STUBS_BUILD=1
else
AC_MSG_RESULT([static])
SHARED_BUILD=0
AC_DEFINE(STATIC_BUILD, 1, [This a static build])
- if test "$stubs_ok" = "yes" ; then
- STUBS_BUILD=1
- else
- STUBS_BUILD=0
- fi
+ if test "$stubs_ok" = "yes" ; then
+ STUBS_BUILD=1
+ else
+ STUBS_BUILD=0
+ fi
fi
if test "${STUBS_BUILD}" = "1" ; then
AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs])
AC_DEFINE(USE_TCLOO_STUBS, 1, [Use TclOO stubs])
if test "${TEA_WINDOWINGSYSTEM}" != ""; then
- AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
+ AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs])
fi
fi
@@ -1177,21 +1193,21 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
fi
if test "$GCC" != "yes" ; then
- if test "${SHARED_BUILD}" = "0" ; then
+ if test "${SHARED_BUILD}" = "0" ; then
runtime=-MT
- else
+ else
runtime=-MD
- fi
- case "x`echo \${VisualStudioVersion}`" in
- x1[[4-9]]*)
- lflags="${lflags} -nodefaultlib:libucrt.lib"
- TEA_ADD_LIBS([ucrt.lib])
- ;;
- *)
- ;;
- esac
-
- if test "$do64bit" != "no" ; then
+ fi
+ case "x`echo \${VisualStudioVersion}`" in
+ x1[[4-9]]*)
+ lflags="${lflags} -nodefaultlib:libucrt.lib"
+ TEA_ADD_LIBS([ucrt.lib])
+ ;;
+ *)
+ ;;
+ esac
+
+ if test "$do64bit" != "no" ; then
CC="cl.exe"
RC="rc.exe"
lflags="${lflags} -nologo -MACHINE:${MACHINE} "
@@ -1490,14 +1506,14 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
# Check to enable 64-bit flags for compiler/linker
AS_IF([test "$do64bit" = yes], [
- AS_IF([test "$GCC" = yes], [
- AC_MSG_WARN([64bit mode not supported by gcc])
- ], [
- do64bit_ok=yes
- SHLIB_LD="ld -64 -shared -rdata_shared"
- CFLAGS="$CFLAGS -64"
- LDFLAGS_ARCH="-64"
- ])
+ AS_IF([test "$GCC" = yes], [
+ AC_MSG_WARN([64bit mode not supported by gcc])
+ ], [
+ do64bit_ok=yes
+ SHLIB_LD="ld -64 -shared -rdata_shared"
+ CFLAGS="$CFLAGS -64"
+ LDFLAGS_ARCH="-64"
+ ])
])
;;
Linux*|GNU*|NetBSD-Debian|DragonFly-*|FreeBSD-*)
@@ -1519,7 +1535,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LDFLAGS="$LDFLAGS $PTHREAD_LIBS"])
;;
- esac
+ esac
AS_IF([test $doRpath = yes], [
CC_SEARCH_FLAGS='"-Wl,-rpath,${LIB_RUNTIME_DIR}"'])
@@ -1724,9 +1740,9 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
# Digital OSF/1
SHLIB_CFLAGS=""
AS_IF([test "$SHARED_BUILD" = 1], [
- SHLIB_LD='ld -shared -expect_unresolved "*"'
+ SHLIB_LD='ld -shared -expect_unresolved "*"'
], [
- SHLIB_LD='ld -non_shared -expect_unresolved "*"'
+ SHLIB_LD='ld -non_shared -expect_unresolved "*"'
])
SHLIB_SUFFIX=".so"
AS_IF([test $doRpath = yes], [
@@ -1896,7 +1912,7 @@ AC_DEFUN([TEA_CONFIG_CFLAGS], [
LDFLAGS="$LDFLAGS -Wl,-Bexport"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[int i;]])],
[tcl_cv_ld_Bexport=yes],[tcl_cv_ld_Bexport=no])
- LDFLAGS=$hold_ldflags])
+ LDFLAGS=$hold_ldflags])
AS_IF([test $tcl_cv_ld_Bexport = yes], [
LDFLAGS="$LDFLAGS -Wl,-Bexport"
])
@@ -2015,8 +2031,8 @@ dnl # preprocessing tests use only CPPFLAGS.
SHORT s;
LONG l;
]])],
- [tcl_cv_winnt_ignore_void=yes],
- [tcl_cv_winnt_ignore_void=no])
+ [tcl_cv_winnt_ignore_void=yes],
+ [tcl_cv_winnt_ignore_void=no])
)
if test "$tcl_cv_winnt_ignore_void" = "yes" ; then
AC_DEFINE(HAVE_WINNT_IGNORE_VOID, 1,
@@ -2529,20 +2545,19 @@ AC_DEFUN([TEA_TCL_LINK_LIBS], [
#
# Might define the following vars:
# _ISOC99_SOURCE
-# _LARGEFILE64_SOURCE
-# _LARGEFILE_SOURCE64
+# _FILE_OFFSET_BITS
#
#--------------------------------------------------------------------
AC_DEFUN([TEA_TCL_EARLY_FLAG],[
AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]),
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[$2]], [[$3]])],
- [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ 1
+ [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no,[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[[#define ]$1[ ]m4_default([$4],[1])[
]$2]], [[$3]])],
[tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes,
[tcl_cv_flag_]translit($1,[A-Z],[a-z])=no)]))
if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then
- AC_DEFINE($1, 1, [Add the ]$1[ flag when building])
+ AC_DEFINE($1, m4_default([$4],[1]), [Add the ]$1[ flag when building])
tcl_flags="$tcl_flags $1"
fi
])
@@ -2552,10 +2567,10 @@ AC_DEFUN([TEA_TCL_EARLY_FLAGS],[
tcl_flags=""
TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ],
[char *p = (char *)strtoll; char *q = (char *)strtoull;])
- TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ],
- [struct stat64 buf; int i = stat64("/", &buf);])
- TEA_TCL_EARLY_FLAG(_LARGEFILE_SOURCE64,[#include ],
- [char *p = (char *)open64;])
+ if test "${TCL_MAJOR_VERSION}" -ne 8 ; then
+ TEA_TCL_EARLY_FLAG(_FILE_OFFSET_BITS,[#include ],
+ [switch (0) { case 0: case (sizeof(off_t)==sizeof(long long)): ; }],64)
+ fi
if test "x${tcl_flags}" = "x" ; then
AC_MSG_RESULT([none])
else
@@ -2579,6 +2594,7 @@ AC_DEFUN([TEA_TCL_EARLY_FLAGS],[
# HAVE_STRUCT_DIRENT64, HAVE_DIR64
# HAVE_STRUCT_STAT64
# HAVE_TYPE_OFF64_T
+# _TIME_BITS
#
#--------------------------------------------------------------------
@@ -2592,9 +2608,9 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
# See if we could use long anyway Note that we substitute in the
# type that is our current guess for a 64-bit type inside this check
# program, so it should be modified only carefully...
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) {
- case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ;
- }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[switch (0) {
+ case 1: case (sizeof(${tcl_type_64bit})==sizeof(long)): ;
+ }]])],[tcl_cv_type_64bit=${tcl_type_64bit}],[])])
if test "${tcl_cv_type_64bit}" = none ; then
AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Do 'long' and 'long long' have the same size (64-bit)?])
AC_MSG_RESULT([yes])
@@ -2609,6 +2625,25 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
AC_MSG_RESULT([${tcl_cv_type_64bit}])
# Now check for auxiliary declarations
+ if test "${TCL_MAJOR_VERSION}" -ne 8 ; then
+ AC_CACHE_CHECK([for 64-bit time_t], tcl_cv_time_t_64,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]],
+ [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])],
+ [tcl_cv_time_t_64=yes],[tcl_cv_time_t_64=no])])
+ if test "x${tcl_cv_time_t_64}" = "xno" ; then
+ # Note that _TIME_BITS=64 requires _FILE_OFFSET_BITS=64
+ # which SC_TCL_EARLY_FLAGS has defined if necessary.
+ AC_CACHE_CHECK([if _TIME_BITS=64 enables 64-bit time_t], tcl_cv__time_bits,[
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _TIME_BITS 64
+#include ]],
+ [[switch (0) {case 0: case (sizeof(time_t)==sizeof(long long)): ;}]])],
+ [tcl_cv__time_bits=yes],[tcl_cv__time_bits=no])])
+ if test "x${tcl_cv__time_bits}" = "xyes" ; then
+ AC_DEFINE(_TIME_BITS, 64, [_TIME_BITS=64 enables 64-bit time_t.])
+ fi
+ fi
+ fi
+
AC_CACHE_CHECK([for struct dirent64], tcl_cv_struct_dirent64,[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include
#include ]], [[struct dirent64 p;]])],
@@ -2620,7 +2655,7 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
AC_CACHE_CHECK([for DIR64], tcl_cv_DIR64,[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include
#include ]], [[struct dirent64 *p; DIR64 d = opendir64(".");
- p = readdir64(d); rewinddir64(d); closedir64(d);]])],
+ p = readdir64(d); rewinddir64(d); closedir64(d);]])],
[tcl_cv_DIR64=yes], [tcl_cv_DIR64=no])])
if test "x${tcl_cv_DIR64}" = "xyes" ; then
AC_DEFINE(HAVE_DIR64, 1, [Is 'DIR64' in ?])
@@ -2643,8 +2678,8 @@ AC_DEFUN([TEA_TCL_64BIT_FLAGS], [
dnl Define HAVE_TYPE_OFF64_T only when the off64_t type and the
dnl functions lseek64 and open64 are defined.
if test "x${tcl_cv_type_off64_t}" = "xyes" && \
- test "x${ac_cv_func_lseek64}" = "xyes" && \
- test "x${ac_cv_func_open64}" = "xyes" ; then
+ test "x${ac_cv_func_lseek64}" = "xyes" && \
+ test "x${ac_cv_func_open64}" = "xyes" ; then
AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?])
AC_MSG_RESULT([yes])
else
@@ -2747,8 +2782,6 @@ The PACKAGE_NAME variable must be defined by your TEA configure.ac])
AC_SUBST(PKG_LIB_FILE)
AC_SUBST(PKG_LIB_FILE8)
AC_SUBST(PKG_LIB_FILE9)
- # Substitute STUB_LIB_FILE in case package creates a stub library too.
- AC_SUBST(PKG_STUB_LIB_FILE)
# We AC_SUBST these here to ensure they are subst'ed,
# in case the user doesn't call TEA_ADD_...
@@ -3106,11 +3139,15 @@ AC_DEFUN([TEA_SETUP_COMPILER], [
fi
fi
+ if test "${TCL_MAJOR_VERSION}" -lt 9 -a "${TCL_MINOR_VERSION}" -lt 7; then
+ AC_DEFINE(Tcl_Size, int, [Is 'Tcl_Size' in ?])
+ fi
+
#--------------------------------------------------------------------
# Common compiler flag setup
#--------------------------------------------------------------------
- AC_C_BIGENDIAN
+ AC_C_BIGENDIAN(,,,[#])
])
#------------------------------------------------------------------------
@@ -3174,10 +3211,11 @@ print("manifest needed")
PACKAGE_LIB_PREFIX8="${PACKAGE_LIB_PREFIX}"
PACKAGE_LIB_PREFIX9="${PACKAGE_LIB_PREFIX}tcl9"
- if test "${TCL_MAJOR_VERSION}" -gt 8 ; then
+ if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then
PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX9}"
else
PACKAGE_LIB_PREFIX="${PACKAGE_LIB_PREFIX8}"
+ AC_DEFINE(TCL_MAJOR_VERSION, 8, [Compile for Tcl8?])
fi
if test "${TEA_PLATFORM}" = "windows" ; then
if test "${SHARED_BUILD}" = "1" ; then
@@ -3202,7 +3240,11 @@ print("manifest needed")
eval eval "PKG_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then
+ eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a"
+ else
+ eval eval "PKG_STUB_LIB_FILE=${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ fi
if test "$GCC" = "yes"; then
PKG_STUB_LIB_FILE=lib${PKG_STUB_LIB_FILE}
fi
@@ -3221,12 +3263,16 @@ print("manifest needed")
eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${SHARED_LIB_SUFFIX}"
RANLIB=:
else
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
- eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE8=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
+ eval eval "PKG_LIB_FILE9=lib${PACKAGE_LIB_PREFIX9}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
eval eval "PKG_LIB_FILE=lib${PACKAGE_LIB_PREFIX}${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}"
fi
# Some packages build their own stubs libraries
- eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then
+ eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub.a"
+ else
+ eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_LIB_PREFIX8}${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}"
+ fi
fi
# These are escaped so that only CFLAGS is picked up at configure time.
@@ -3240,6 +3286,8 @@ print("manifest needed")
AC_SUBST(MAKE_SHARED_LIB)
AC_SUBST(MAKE_STATIC_LIB)
AC_SUBST(MAKE_STUB_LIB)
+ # Substitute STUB_LIB_FILE in case package creates a stub library too.
+ AC_SUBST(PKG_STUB_LIB_FILE)
AC_SUBST(RANLIB_STUB)
AC_SUBST(VC_MANIFEST_EMBED_DLL)
AC_SUBST(VC_MANIFEST_EMBED_EXE)
@@ -3366,9 +3414,9 @@ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [
# any *_NATIVE vars be defined in the Makefile
TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}"
if test "`uname -s`" = "Darwin"; then
- # If Tcl was built as a framework, attempt to use
- # the framework's Headers and PrivateHeaders directories
- case ${TCL_DEFS} in
+ # If Tcl was built as a framework, attempt to use
+ # the framework's Headers and PrivateHeaders directories
+ case ${TCL_DEFS} in
*TCL_FRAMEWORK*)
if test -d "${TCL_BIN_DIR}/Headers" -a \
-d "${TCL_BIN_DIR}/PrivateHeaders"; then
@@ -3376,7 +3424,7 @@ AC_DEFUN([TEA_PRIVATE_TCL_HEADERS], [
else
TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`"
fi
- ;;
+ ;;
esac
result="Using ${TCL_INCLUDES}"
else
@@ -3817,10 +3865,10 @@ AC_DEFUN([TEA_LOAD_CONFIG], [
AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh])
if test -f "${$1_BIN_DIR}/$1Config.sh" ; then
- AC_MSG_RESULT([loading])
+ AC_MSG_RESULT([loading])
. "${$1_BIN_DIR}/$1Config.sh"
else
- AC_MSG_RESULT([file not found])
+ AC_MSG_RESULT([file not found])
fi
#
@@ -3834,11 +3882,11 @@ AC_DEFUN([TEA_LOAD_CONFIG], [
if test -f "${$1_BIN_DIR}/Makefile" ; then
AC_MSG_WARN([Found Makefile - using build library specs for $1])
- $1_LIB_SPEC=${$1_BUILD_LIB_SPEC}
- $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC}
- $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH}
- $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC}
- $1_LIBRARY_PATH=${$1_LIBRARY_PATH}
+ $1_LIB_SPEC=${$1_BUILD_LIB_SPEC}
+ $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC}
+ $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH}
+ $1_INCLUDE_SPEC=${$1_BUILD_INCLUDE_SPEC}
+ $1_LIBRARY_PATH=${$1_LIBRARY_PATH}
fi
AC_SUBST($1_VERSION)
@@ -3919,6 +3967,10 @@ AC_DEFUN([TEA_EXPORT_CONFIG], [
eval $1_LIB_FLAG="-l$1`echo ${PACKAGE_VERSION} | tr -d .`"
eval $1_STUB_LIB_FLAG="-l$1stub`echo ${PACKAGE_VERSION} | tr -d .`"
fi
+ if test "${TCL_MAJOR_VERSION}" -gt 8 -a x"${with_tcl8}" = x; then
+ eval $1_STUB_LIB_FLAG="-l$1stub"
+ fi
+
$1_BUILD_LIB_SPEC="-L`$CYGPATH $(pwd)` ${$1_LIB_FLAG}"
$1_LIB_SPEC="-L`$CYGPATH ${pkglibdir}` ${$1_LIB_FLAG}"
$1_BUILD_STUB_LIB_SPEC="-L`$CYGPATH $(pwd)` [$]{$1_STUB_LIB_FLAG}"
@@ -4008,52 +4060,52 @@ AC_DEFUN([TEA_ZIPFS_SUPPORT], [
AC_CACHE_VAL(ac_cv_path_macher, [
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
- for j in `ls -r $dir/macher 2> /dev/null` \
- `ls -r $dir/macher 2> /dev/null` ; do
- if test x"$ac_cv_path_macher" = x ; then
- if test -f "$j" ; then
- ac_cv_path_macher=$j
- break
- fi
- fi
- done
+ for j in `ls -r $dir/macher 2> /dev/null` \
+ `ls -r $dir/macher 2> /dev/null` ; do
+ if test x"$ac_cv_path_macher" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_macher=$j
+ break
+ fi
+ fi
+ done
done
])
if test -f "$ac_cv_path_macher" ; then
- MACHER_PROG="$ac_cv_path_macher"
- AC_MSG_RESULT([$MACHER_PROG])
- AC_MSG_RESULT([Found macher in environment])
+ MACHER_PROG="$ac_cv_path_macher"
+ AC_MSG_RESULT([$MACHER_PROG])
+ AC_MSG_RESULT([Found macher in environment])
fi
AC_MSG_CHECKING([for zip])
AC_CACHE_VAL(ac_cv_path_zip, [
search_path=`echo ${PATH} | sed -e 's/:/ /g'`
for dir in $search_path ; do
- for j in `ls -r $dir/zip 2> /dev/null` \
- `ls -r $dir/zip 2> /dev/null` ; do
- if test x"$ac_cv_path_zip" = x ; then
- if test -f "$j" ; then
- ac_cv_path_zip=$j
- break
- fi
- fi
- done
+ for j in `ls -r $dir/zip 2> /dev/null` \
+ `ls -r $dir/zip 2> /dev/null` ; do
+ if test x"$ac_cv_path_zip" = x ; then
+ if test -f "$j" ; then
+ ac_cv_path_zip=$j
+ break
+ fi
+ fi
+ done
done
])
if test -f "$ac_cv_path_zip" ; then
- ZIP_PROG="$ac_cv_path_zip"
- AC_MSG_RESULT([$ZIP_PROG])
- ZIP_PROG_OPTIONS="-rq"
- ZIP_PROG_VFSSEARCH="*"
- AC_MSG_RESULT([Found INFO Zip in environment])
- # Use standard arguments for zip
+ ZIP_PROG="$ac_cv_path_zip"
+ AC_MSG_RESULT([$ZIP_PROG])
+ ZIP_PROG_OPTIONS="-rq"
+ ZIP_PROG_VFSSEARCH="*"
+ AC_MSG_RESULT([Found INFO Zip in environment])
+ # Use standard arguments for zip
else
- # It is not an error if an installed version of Zip can't be located.
- # We can use the locally distributed minizip instead
- ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
- ZIP_PROG_OPTIONS="-o -r"
- ZIP_PROG_VFSSEARCH="*"
- ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
- AC_MSG_RESULT([No zip found on PATH. Building minizip])
+ # It is not an error if an installed version of Zip can't be located.
+ # We can use the locally distributed minizip instead
+ ZIP_PROG="./minizip${EXEEXT_FOR_BUILD}"
+ ZIP_PROG_OPTIONS="-o -r"
+ ZIP_PROG_VFSSEARCH="*"
+ ZIP_INSTALL_OBJS="minizip${EXEEXT_FOR_BUILD}"
+ AC_MSG_RESULT([No zip found on PATH. Building minizip])
fi
AC_SUBST(MACHER_PROG)
AC_SUBST(ZIP_PROG)
@@ -4064,4 +4116,4 @@ AC_DEFUN([TEA_ZIPFS_SUPPORT], [
# Local Variables:
# mode: autoconf
-# End:
\ No newline at end of file
+# End:
diff --git a/autoconf/tea/win/makefile.vc b/autoconf/tea/win/makefile.vc
index da56e811fc..bb32f1a75c 100644
--- a/autoconf/tea/win/makefile.vc
+++ b/autoconf/tea/win/makefile.vc
@@ -1,430 +1,61 @@
-# makefile.vc -- -*- Makefile -*-
+#------------------------------------------------------------- -*- makefile -*-
#
-# Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
+# Sample makefile for building Tcl extensions.
#
-# This makefile is based upon the Tcl 8.4 Makefile.vc and modified to
-# make it suitable as a general package makefile. Look for the word EDIT
-# which marks sections that may need modification. As a minumum you will
-# need to change the PROJECT, DOTVERSION and DLLOBJS variables to values
-# relevant to your package.
+# Basic build, test and install
+# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl
+# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl test
+# nmake /s /nologo /f makefile.vc INSTALLDIR=c:\path\to\tcl install
+#
+# For other build options (debug, static etc.)
+# See TIP 477 (https://core.tcl.tk/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.
-#
-# Copyright (c) 1995-1996 Sun Microsystems, Inc.
-# Copyright (c) 1998-2000 Ajuba Solutions.
-# Copyright (c) 2001 ActiveState Corporation.
-# Copyright (c) 2001-2002 David Gravereaux.
-# Copyright (c) 2003 Pat Thoyts
#
-#-------------------------------------------------------------------------
-# RCS: @(#)$Id: makefile.vc,v 1.4 2004/07/26 08:22:05 patthoyts Exp $
-#-------------------------------------------------------------------------
-
-!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR)
-MSG = ^
-You will need to run vcvars32.bat from Developer Studio, first, to setup^
-the environment. Jump to this line to read the new instructions.
-!error $(MSG)
-!endif
-
#------------------------------------------------------------------------------
-# HOW TO USE this makefile:
-#
-# 1) It is now necessary to have %MSVCDir% set in the environment. This is
-# used as a check to see if vcvars32.bat had been run prior to running
-# nmake or during the installation of Microsoft Visual C++, MSVCDir had
-# been set globally and the PATH adjusted. Either way is valid.
-#
-# You'll need to run vcvars32.bat contained in the MsDev's vc(98)/bin
-# directory to setup the proper environment, if needed, for your current
-# setup. This is a needed bootstrap requirement and allows the swapping of
-# different environments to be easier.
-#
-# 2) To use the Platform SDK (not expressly needed), run setenv.bat after
-# vcvars32.bat according to the instructions for it. This can also turn on
-# the 64-bit compiler, if your SDK has it.
-#
-# 3) Targets are:
-# all -- Builds everything.
-# -- Builds the project (eg: nmake sample)
-# test -- Builds and runs the test suite.
-# install -- Installs the built binaries and libraries to $(INSTALLDIR)
-# in an appropriate subdirectory.
-# clean/realclean/distclean -- varying levels of cleaning.
-#
-# 4) Macros usable on the commandline:
-# INSTALLDIR=
-# Sets where to install Tcl from the built binaries.
-# C:\Progra~1\Tcl is assumed when not specified.
-#
-# OPTS=static,msvcrt,staticpkg,threads,symbols,profile,loimpact,none
-# Sets special options for the core. The default is for none.
-# Any combination of the above may be used (comma separated).
-# 'none' will over-ride everything to nothing.
-#
-# static = Builds a static library of the core instead of a
-# dll. The shell will be static (and large), as well.
-# msvcrt = Effects the static option only to switch it from
-# using libcmt(d) as the C runtime [by default] to
-# msvcrt(d). This is useful for static embedding
-# support.
-# staticpkg = Effects the static option only to switch
-# tclshXX.exe to have the dde and reg extension linked
-# inside it.
-# threads = Turns on full multithreading support.
-# thrdalloc = Use the thread allocator (shared global free pool).
-# symbols = Adds symbols for step debugging.
-# profile = Adds profiling hooks. Map file is assumed.
-# loimpact = Adds a flag for how NT treats the heap to keep memory
-# in use, low. This is said to impact alloc performance.
-#
-# STATS=memdbg,compdbg,none
-# Sets optional memory and bytecode compiler debugging code added
-# to the core. The default is for none. Any combination of the
-# above may be used (comma separated). 'none' will over-ride
-# everything to nothing.
-#
-# memdbg = Enables the debugging memory allocator.
-# compdbg = Enables byte compilation logging.
-#
-# MACHINE=(IX86|IA64|ALPHA)
-# Set the machine type used for the compiler, linker, and
-# resource compiler. This hook is needed to tell the tools
-# when alternate platforms are requested. IX86 is the default
-# when not specified.
-#
-# TMP_DIR=
-# OUT_DIR=
-# Hooks to allow the intermediate and output directories to be
-# changed. $(OUT_DIR) is assumed to be
-# $(BINROOT)\(Release|Debug) based on if symbols are requested.
-# $(TMP_DIR) will de $(OUT_DIR)\ by default.
-#
-# TESTPAT=
-# Reads the tests requested to be run from this file.
-#
-# CFG_ENCODING=encoding
-# name of encoding for configuration information. Defaults
-# to cp1252
-#
-# 5) Examples:
-#
-# Basic syntax of calling nmake looks like this:
-# nmake [-nologo] -f makefile.vc [target|macrodef [target|macrodef] [...]]
-#
-# Standard (no frills)
-# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
-# Setting environment for using Microsoft Visual C++ tools.
-# c:\tcl_src\win\>nmake -f makefile.vc all
-# c:\tcl_src\win\>nmake -f makefile.vc install INSTALLDIR=c:\progra~1\tcl
-#
-# Building for Win64
-# c:\tcl_src\win\>c:\progra~1\micros~1\vc98\bin\vcvars32.bat
-# Setting environment for using Microsoft Visual C++ tools.
-# c:\tcl_src\win\>c:\progra~1\platfo~1\setenv.bat /pre64 /RETAIL
-# Targeting Windows pre64 RETAIL
-# c:\tcl_src\win\>nmake -f makefile.vc MACHINE=IA64
-#
-#------------------------------------------------------------------------------
-#==============================================================================
-###############################################################################
-#------------------------------------------------------------------------------
-
-!if !exist("makefile.vc")
-MSG = ^
-You must run this makefile only from the directory it is in.^
-Please `cd` to its location first.
-!error $(MSG)
-!endif
-
-#-------------------------------------------------------------------------
-# Project specific information (EDIT)
-#
-# You should edit this with the name and version of your project. This
-# information is used to generate the name of the package library and
-# it's install location.
-#
-# For example, the sample extension is going to build sample04.dll and
-# would install it into $(INSTALLDIR)\lib\sample04
-#
-# You need to specify the object files that need to be linked into your
-# binary here.
-#
-#-------------------------------------------------------------------------
-
-PROJECT = sqlite3
-!include "rules.vc"
-
-# nmakehelp -V will search the file for tag, skips until a
-# number and returns all character until a character not in [0-9.ab]
-# is read.
-
-!if [echo REM = This file is generated from Makefile.vc > versions.vc]
-!endif
-# get project version from row "AC_INIT([sqlite], [3.x.y])"
-!if [echo DOTVERSION = \>> versions.vc] \
- && [nmakehlp -V ..\configure.ac AC_INIT >> versions.vc]
-!endif
-!include "versions.vc"
-
-VERSION = $(DOTVERSION:.=)
-STUBPREFIX = $(PROJECT)stub
-
-#-------------------------------------------------------------------------
-# Target names and paths ( shouldn't need changing )
-#-------------------------------------------------------------------------
-
-BINROOT = .
-ROOT = ..
-
-PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
-PRJLIBNAME = $(PROJECT).$(EXT)
-PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
-
-PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
-PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME)
-### Make sure we use backslash only.
-PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION)
-LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR)
-INCLUDE_INSTALL_DIR = $(_TCLDIR)\include
+# PROJECT is sqlite, not sqlite3 to match TEA AC_INIT definition.
+# This makes the generated DLL name also consistent between the two
+# except for the "t" suffix which is the convention for nmake builds.
+PROJECT = sqlite
+PRJ_PACKAGE_TCLNAME = sqlite3
-### The following paths CANNOT have spaces in them.
-GENERICDIR = $(ROOT)\generic
-WINDIR = $(ROOT)\win
-LIBDIR = $(ROOT)\library
-DOCDIR = $(ROOT)\doc
-TOOLSDIR = $(ROOT)\tools
-COMPATDIR = $(ROOT)\compat
+!include "rules-ext.vc"
-### Figure out where the primary source code file(s) is/are.
-!if exist("$(ROOT)\..\..\sqlite3.c") && exist("$(ROOT)\..\..\src\tclsqlite.c")
-SQL_INCLUDES = -I"$(ROOT)\..\.."
-SQLITE_SRCDIR = $(ROOT)\..\..
-TCLSQLITE_SRCDIR = $(ROOT)\..\..\src
-DLLOBJS = $(TMP_DIR)\sqlite3.obj $(TMP_DIR)\tclsqlite.obj
-!else
-TCLSQLITE_SRCDIR = $(ROOT)\generic
-DLLOBJS = $(TMP_DIR)\tclsqlite3.obj
-!endif
+PRJ_OBJS = $(TMP_DIR)\tclsqlite3.obj
-#---------------------------------------------------------------------
-# Compile flags
-#---------------------------------------------------------------------
-
-!if !$(DEBUG)
-!if $(OPTIMIZING)
-### This cranks the optimization level to maximize speed
-cdebug = -O2 -Op -Gs
-!else
-cdebug =
-!endif
-!else if "$(MACHINE)" == "IA64"
-### Warnings are too many, can't support warnings into errors.
-cdebug = -Z7 -Od -GZ
-!else
-cdebug = -Z7 -WX -Od -GZ
-!endif
-
-### Declarations common to all compiler options
-cflags = -nologo -c -W3 -D_CRT_SECURE_NO_WARNINGS -YX -Fp$(TMP_DIR)^\
-
-!if $(MSVCRT)
-!if $(DEBUG)
-crt = -MDd
-!else
-crt = -MD
-!endif
-!else
-!if $(DEBUG)
-crt = -MTd
-!else
-crt = -MT
-!endif
-!endif
-
-INCLUDES = $(SQL_INCLUDES) $(TCL_INCLUDES) -I"$(WINDIR)" \
- -I"$(GENERICDIR)" -I"$(ROOT)\.."
-BASE_CLFAGS = $(cflags) $(cdebug) $(crt) $(INCLUDES) \
+# Preprocessor macros specific to sqlite3.
+PRJ_DEFINES = -I"$(ROOT)\.." -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE \
+ -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 \
+ -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS4=1 \
+ -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 \
+ -DSQLITE_ENABLE_JSON1=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS=1 \
-DSQLITE_3_SUFFIX_ONLY=1 -DSQLITE_ENABLE_RTREE=1 \
- -DSQLITE_ENABLE_FTS3=1 -DSQLITE_OMIT_DEPRECATED=1 \
- -DSQLITE_ENABLE_FTS4=1 \
- -DSQLITE_ENABLE_FTS5=1 \
- -DSQLITE_3_SUFFIX_ONLY=1 \
- -DSQLITE_ENABLE_RTREE=1 \
- -DSQLITE_ENABLE_GEOPOLY=1 \
- -DSQLITE_ENABLE_MATH_FUNCTIONS=1 \
- -DSQLITE_ENABLE_DESERIALIZE=1 \
- -DSQLITE_ENABLE_DBPAGE_VTAB=1 \
- -DSQLITE_ENABLE_BYTECODE_VTAB=1 \
- -DSQLITE_ENABLE_DBSTAT_VTAB=1
-
-CON_CFLAGS = $(cflags) $(cdebug) $(crt) -DCONSOLE -DSQLITE_ENABLE_FTS3=1
-TCL_CFLAGS = -DBUILD_sqlite -DUSE_TCL_STUBS \
- -DPACKAGE_VERSION="\"$(DOTVERSION)\"" $(BASE_CLFAGS) \
- $(OPTDEFINES)
-
-#---------------------------------------------------------------------
-# Link flags
-#---------------------------------------------------------------------
-
-!if $(DEBUG)
-ldebug = -debug:full -debugtype:cv
-!else
-ldebug = -release -opt:ref -opt:icf,3
-!endif
-
-### Declarations common to all linker options
-lflags = -nologo -machine:$(MACHINE) $(ldebug)
-
-!if $(PROFILE)
-lflags = $(lflags) -profile
-!endif
-
-!if $(ALIGN98_HACK) && !$(STATIC_BUILD)
-### Align sections for PE size savings.
-lflags = $(lflags) -opt:nowin98
-!else if !$(ALIGN98_HACK) && $(STATIC_BUILD)
-### Align sections for speed in loading by choosing the virtual page size.
-lflags = $(lflags) -align:4096
-!endif
-
-!if $(LOIMPACT)
-lflags = $(lflags) -ws:aggressive
-!endif
-
-dlllflags = $(lflags) -dll
-conlflags = $(lflags) -subsystem:console
-guilflags = $(lflags) -subsystem:windows
-baselibs = $(TCLSTUBLIB)
-
-#---------------------------------------------------------------------
-# TclTest flags
-#---------------------------------------------------------------------
-
-!IF "$(TESTPAT)" != ""
-TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
-!ENDIF
-
-#---------------------------------------------------------------------
-# Project specific targets (EDIT)
-#---------------------------------------------------------------------
-
-all: setup $(PROJECT)
-$(PROJECT): setup $(PRJLIB)
-install: install-binaries install-libraries install-docs
-
-# Tests need to ensure we load the right dll file we
-# have to handle the output differently on Win9x.
-#
-!if "$(OS)" == "Windows_NT" || "$(MSVCDIR)" == "IDE"
-test: setup $(PROJECT)
- set TCL_LIBRARY=$(ROOT)/library
- $(TCLSH) <<
-load $(PRJLIB:\=/)
-cd "$(ROOT)/tests"
-set argv "$(TESTFLAGS)"
-source all.tcl
-<<
-!else
-test: setup $(PROJECT)
- echo Please wait while the test results are collected
- set TCL_LIBRARY=$(ROOT)/library
- $(TCLSH) << >tests.log
-load $(PRJLIB:\=/)
-cd "$(ROOT)/tests"
-set argv "$(TESTFLAGS)"
-source all.tcl
-<<
- type tests.log | more
-!endif
-
-setup:
- @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)
- @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
-
-$(PRJLIB): $(DLLOBJS)
- $(link32) $(dlllflags) -out:$@ $(baselibs) @<<
-$**
-<<
- -@del $*.exp
-
-$(PRJSTUBLIB): $(PRJSTUBOBJS)
- $(lib32) -nologo -out:$@ $(PRJSTUBOBJS)
-
-#---------------------------------------------------------------------
-# Implicit rules
-#---------------------------------------------------------------------
-
-$(TMP_DIR)\sqlite3.obj: $(SQLITE_SRCDIR)\sqlite3.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(SQLITE_SRCDIR)\sqlite3.c
-
-$(TMP_DIR)\tclsqlite.obj: $(TCLSQLITE_SRCDIR)\tclsqlite.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(TCLSQLITE_SRCDIR)\tclsqlite.c
-
-$(TMP_DIR)\tclsqlite3.obj: $(TCLSQLITE_SRCDIR)\tclsqlite3.c
- $(cc32) $(TCL_CFLAGS) -DBUILD_$(PROJECT) -Fo$(TMP_DIR)\ \
- -c $(TCLSQLITE_SRCDIR)\tclsqlite3.c
-
-{$(WINDIR)}.rc{$(TMP_DIR)}.res:
- $(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \
-!if $(DEBUG)
- -d DEBUG \
-!endif
-!if $(TCL_THREADS)
- -d TCL_THREADS \
-!endif
-!if $(STATIC_BUILD)
- -d STATIC_BUILD \
-!endif
- $<
-
-.SUFFIXES:
-.SUFFIXES:.c .rc
-
-#---------------------------------------------------------------------
-# Installation. (EDIT)
-#
-# You may need to modify this section to reflect the final distribution
-# of your files and possibly to generate documentation.
-#
-#---------------------------------------------------------------------
-
-install-binaries:
- @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)'
- @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
- @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL
-
-install-libraries:
- @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
- @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
- @echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
- @type << >"$(SCRIPT_INSTALL_DIR)\pkgIndex.tcl"
-package ifneeded $(PROJECT) $(DOTVERSION) \
- [list load [file join $$dir $(PRJLIBNAME)] sqlite3]
-<<
-
-install-docs:
- @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
- @if exist $(DOCDIR) $(CPY) $(DOCDIR)\*.n "$(DOC_INSTALL_DIR)"
-
-#---------------------------------------------------------------------
-# Clean up
-#---------------------------------------------------------------------
-
-clean:
- @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
- @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc
-
-realclean: clean
- @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
-
-distclean: realclean
- @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe
- @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj
+ -DSQLITE_UNTESTABLE=1 -DSQLITE_OMIT_LOOKASIDE=1 \
+ -DSQLITE_SECURE_DELETE=1 -DSQLITE_SOUNDEX=1 -DSQLITE_ENABLE_GEOPOLY=1 \
+ -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1 \
+ -DSQLITE_ENABLE_MATH_FUNCTIONS=1 -DDSQLITE_USE_ALLOCA=1 \
+ -DSQLITE_ENABLE_STAT4=1 -DSQLITE_OMIT_DEPRECATED=1 \
+ -DSQLITE_WIN32_GETVERSIONEX=0 -DSQLITE_WIN32_NO_ANSI=1
+PRJ_DEFINES = $(PRJ_DEFINES) -I$(TMP_DIR)
+
+# Standard targets to build, install, test etc.
+!include "$(_RULESDIR)\targets.vc"
+
+# The built-in pkgindex does no suffice for our extension as
+# the PROJECT name (sqlite) is not same as init function name (Sqlite3)
+pkgindex:
+ @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PRJLIBNAME9)] [string totitle $(PRJ_PACKAGE_TCLNAME)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } else { >> $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PRJLIBNAME8)] [string totitle $(PRJ_PACKAGE_TCLNAME)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } >> $(OUT_DIR)\pkgIndex.tcl
+
+# Install the manpage though on Windows, doubt it does much good
+install: default-install-docs-n
+
+# Explicit dependency rules
diff --git a/autoconf/tea/win/rules-ext.vc b/autoconf/tea/win/rules-ext.vc
new file mode 100644
index 0000000000..479720a4bc
--- /dev/null
+++ b/autoconf/tea/win/rules-ext.vc
@@ -0,0 +1,123 @@
+# 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 "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
+!if [$(CC) -nologo -DNDEBUG "nmakehlp.c" -link -subsystem:console > nul]
+!endif
+!else
+!if [copy x86_64-w64-mingw32-nmakehlp.exe nmakehlp.exe >NUL]
+!endif
+!endif
+
+# First locate the Tcl directory that we are working with.
+!if "$(TCLDIR)" != ""
+
+_RULESDIR = $(TCLDIR:/=\)
+
+!else
+
+# If an installation path is specified, that is also the Tcl directory.
+# Also Tk never builds against an installed Tcl, it needs Tcl sources
+!if defined(INSTALLDIR) && "$(PROJECT)" != "tk"
+_RULESDIR=$(INSTALLDIR:/=\)
+!else
+# Locate Tcl sources
+!if [echo _RULESDIR = \> nmakehlp.out] \
+ || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
+_RULESDIR = ..\..\tcl
+!else
+!include nmakehlp.out
+!endif
+
+!endif # defined(INSTALLDIR)....
+
+!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
\ No newline at end of file
diff --git a/autoconf/tea/win/rules.vc b/autoconf/tea/win/rules.vc
index 99471053c8..8ecce0e106 100644
--- a/autoconf/tea/win/rules.vc
+++ b/autoconf/tea/win/rules.vc
@@ -1,31 +1,139 @@
-#------------------------------------------------------------------------------
+#------------------------------------------------------------- -*- makefile -*-
# rules.vc --
#
-# Microsoft Visual C++ makefile include for decoding the commandline
-# macros. This file does not need editing to build Tcl.
+# Part of the nmake based build system for Tcl and its extensions.
+# This file does all the hard work in terms of parsing build options,
+# compiler switches, defining common targets and macros. The Tcl makefile
+# directly includes this. Extensions include it via "rules-ext.vc".
+#
+# See TIP 477 (https://core.tcl-lang.org/tips/doc/main/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.
#
# Copyright (c) 2001-2003 David Gravereaux.
# Copyright (c) 2003-2008 Patrick Thoyts
+# Copyright (c) 2017 Ashok P. Nadkarni
#------------------------------------------------------------------------------
!ifndef _RULES_VC
_RULES_VC = 1
-cc32 = $(CC) # built-in default.
-link32 = link
-lib32 = lib
-rc32 = $(RC) # built-in default.
+# The following macros define the version of the rules.vc nmake build system
+# For modifications that are not backward-compatible, you *must* change
+# the major version.
+RULES_VERSION_MAJOR = 1
+RULES_VERSION_MINOR = 12
-!ifndef INSTALLDIR
-### Assume the normal default.
-_INSTALLDIR = C:\Program Files\Tcl
+# The PROJECT macro must be defined by parent makefile.
+!if "$(PROJECT)" == ""
+!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc
+!endif
+
+!if "$(PRJ_PACKAGE_TCLNAME)" == ""
+PRJ_PACKAGE_TCLNAME = $(PROJECT)
+!endif
+
+# Also special case Tcl and Tk to save some typing later
+DOING_TCL = 0
+DOING_TK = 0
+!if "$(PROJECT)" == "tcl"
+DOING_TCL = 1
+!elseif "$(PROJECT)" == "tk"
+DOING_TK = 1
+!endif
+
+!ifndef NEED_TK
+# Backwards compatibility
+!ifdef PROJECT_REQUIRES_TK
+NEED_TK = $(PROJECT_REQUIRES_TK)
!else
-### Fix the path separators.
-_INSTALLDIR = $(INSTALLDIR:/=\)
+NEED_TK = 0
+!endif
+!endif
+
+!ifndef NEED_TCL_SOURCE
+NEED_TCL_SOURCE = 0
+!endif
+
+!ifdef NEED_TK_SOURCE
+!if $(NEED_TK_SOURCE)
+NEED_TK = 1
!endif
+!else
+NEED_TK_SOURCE = 0
+!endif
+
+################################################################
+# Nmake is a pretty weak environment in syntax and capabilities
+# so this file is necessarily verbose. It's broken down into
+# the following parts.
+#
+# 0. Sanity check that compiler environment is set up and initialize
+# any built-in settings from the parent makefile
+# 1. First define the external tools used for compiling, copying etc.
+# as this is independent of everything else.
+# 2. Figure out our build structure in terms of the directory, whether
+# we are building Tcl or an extension, etc.
+# 3. Determine the compiler and linker versions
+# 4. Build the nmakehlp helper application
+# 5. Determine the supported compiler options and features
+# 6. Extract Tcl, Tk, and possibly extensions, version numbers from the
+# headers
+# 7. Parse the OPTS macro value for user-specified build configuration
+# 8. Parse the STATS macro value for statistics instrumentation
+# 9. Parse the CHECKS macro for additional compilation checks
+# 10. Based on this selected configuration, construct the output
+# directory and file paths
+# 11. Construct the paths where the package is to be installed
+# 12. Set up the actual options passed to compiler and linker based
+# on the information gathered above.
+# 13. Define some standard build targets and implicit rules. These may
+# be optionally disabled by the parent makefile.
+# 14. (For extensions only.) Compare the configuration of the target
+# Tcl and the extensions and warn against discrepancies.
+#
+# One final note about the macro names used. They are as they are
+# for historical reasons. We would like legacy extensions to
+# continue to work with this make include file so be wary of
+# changing them for consistency or clarity.
+
+# 0. Sanity check compiler environment
+
+# Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or
+# VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir)
+
+!if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR)
+MSG = ^
+Visual C++ compiler environment not initialized.
+!error $(MSG)
+!endif
+
+# 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
+
+
+################################################################
+# 1. Define external programs being used
#----------------------------------------------------------
# Set the proper copy method to avoid overwrite questions
@@ -33,28 +141,291 @@ _INSTALLDIR = $(INSTALLDIR:/=\)
# "delete all" method.
#----------------------------------------------------------
-!if "$(OS)" == "Windows_NT"
RMDIR = rmdir /S /Q
-ERRNULL = 2>NUL
-!if ![ver | find "4.0" > nul]
-CPY = echo y | xcopy /i >NUL
-COPY = copy >NUL
-!else
CPY = xcopy /i /y >NUL
+CPYDIR = xcopy /e /i /y >NUL
COPY = copy /y >NUL
+MKDIR = mkdir
+
+######################################################################
+# 2. Figure out our build environment in terms of what we're building.
+#
+# (a) Tcl itself
+# (b) Tk
+# (c) a Tcl extension using libraries/includes from an *installed* Tcl
+# (d) a Tcl extension using libraries/includes from Tcl source directory
+#
+# This last is needed because some extensions still need
+# some Tcl interfaces that are not publicly exposed.
+#
+# The fragment will set the following macros:
+# ROOT - root of this module sources
+# COMPATDIR - source directory that holds compatibility sources
+# DOCDIR - source directory containing documentation files
+# GENERICDIR - platform-independent source directory
+# WIN_DIR - Windows-specific source directory
+# TESTDIR - directory containing test files
+# TOOLSDIR - directory containing build tools
+# _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set
+# when building Tcl itself.
+# _INSTALLDIR - native form of the installation path. For Tcl
+# this will be the root of the Tcl installation. For extensions
+# this will be the lib directory under the root.
+# TCLINSTALL - set to 1 if _TCLDIR refers to
+# headers and libraries from an installed Tcl, and 0 if built against
+# Tcl sources. Not set when building Tcl itself. Yes, not very well
+# named.
+# _TCL_H - native path to the tcl.h file
+#
+# If Tk is involved, also sets the following
+# _TKDIR - native form Tk installation OR Tk source. Not set if building
+# Tk itself.
+# TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources
+# _TK_H - native path to the tk.h file
+
+# Root directory for sources and assumed subdirectories
+ROOT = $(MAKEDIR)\..
+# The following paths CANNOT have spaces in them as they appear on the
+# left side of implicit rules.
+!ifndef COMPATDIR
+COMPATDIR = $(ROOT)\compat
+!endif
+!ifndef DOCDIR
+DOCDIR = $(ROOT)\doc
+!endif
+!ifndef GENERICDIR
+GENERICDIR = $(ROOT)\generic
+!endif
+!ifndef TOOLSDIR
+TOOLSDIR = $(ROOT)\tools
+!endif
+!ifndef TESTDIR
+TESTDIR = $(ROOT)\tests
+!endif
+!ifndef LIBDIR
+!if exist("$(ROOT)\library")
+LIBDIR = $(ROOT)\library
+!else
+LIBDIR = $(ROOT)\lib
!endif
-!else # "$(OS)" != "Windows_NT"
-CPY = xcopy /i >_JUNK.OUT # On Win98 NUL does not work here.
-COPY = copy >_JUNK.OUT # On Win98 NUL does not work here.
-RMDIR = deltree /Y
-NULL = \NUL # Used in testing directory existence
-ERRNULL = >NUL # Win9x shell cannot redirect stderr
!endif
-MKDIR = mkdir
+!ifndef DEMODIR
+!if exist("$(LIBDIR)\demos")
+DEMODIR = $(LIBDIR)\demos
+!else
+DEMODIR = $(ROOT)\demos
+!endif
+!endif # ifndef DEMODIR
+# Do NOT use WINDIR because it is Windows internal environment
+# variable to point to c:\windows!
+WIN_DIR = $(ROOT)\win
-#------------------------------------------------------------------------------
-# Determine the host and target architectures and compiler version.
-#------------------------------------------------------------------------------
+!ifndef RCDIR
+!if exist("$(WIN_DIR)\rc")
+RCDIR = $(WIN_DIR)\rc
+!else
+RCDIR = $(WIN_DIR)
+!endif
+!endif
+RCDIR = $(RCDIR:/=\)
+
+# The target directory where the built packages and binaries will be installed.
+# INSTALLDIR is the (optional) path specified by the user.
+# _INSTALLDIR is INSTALLDIR using the backslash separator syntax
+!ifdef INSTALLDIR
+### Fix the path separators.
+_INSTALLDIR = $(INSTALLDIR:/=\)
+!else
+### Assume the normal default.
+_INSTALLDIR = $(HOMEDRIVE)\Tcl
+!endif
+
+!if $(DOING_TCL)
+
+# BEGIN Case 2(a) - Building Tcl itself
+
+# Only need to define _TCL_H
+_TCL_H = ..\generic\tcl.h
+
+# END Case 2(a) - Building Tcl itself
+
+!elseif $(DOING_TK)
+
+# BEGIN Case 2(b) - Building Tk
+
+TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl
+!if "$(TCLDIR)" == ""
+!if [echo TCLDIR = \> nmakehlp.out] \
+ || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
+!error *** Could not locate Tcl source directory.
+!endif
+!include nmakehlp.out
+!endif # TCLDIR == ""
+
+_TCLDIR = $(TCLDIR:/=\)
+_TCL_H = $(_TCLDIR)\generic\tcl.h
+!if !exist("$(_TCL_H)")
+!error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory.
+!endif
+
+_TK_H = ..\generic\tk.h
+
+# END Case 2(b) - Building Tk
+
+!else
+
+# BEGIN Case 2(c) or (d) - Building an extension other than Tk
+
+# If command line has specified Tcl location through TCLDIR, use it
+# else default to the INSTALLDIR setting
+!if "$(TCLDIR)" != ""
+
+_TCLDIR = $(TCLDIR:/=\)
+!if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined
+TCLINSTALL = 1
+_TCL_H = $(_TCLDIR)\include\tcl.h
+!elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined
+TCLINSTALL = 0
+_TCL_H = $(_TCLDIR)\generic\tcl.h
+!endif
+
+!else # # Case 2(c) for extensions with TCLDIR undefined
+
+# Need to locate Tcl depending on whether it needs Tcl source or not.
+# If we don't, check the INSTALLDIR for an installed Tcl first
+
+!if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE)
+
+TCLINSTALL = 1
+TCLDIR = $(_INSTALLDIR)\..
+# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
+# later so the \.. accounts for the /lib
+_TCLDIR = $(_INSTALLDIR)\..
+_TCL_H = $(_TCLDIR)\include\tcl.h
+
+!else # exist(...) && !$(NEED_TCL_SOURCE)
+
+!if [echo _TCLDIR = \> nmakehlp.out] \
+ || [nmakehlp -L generic\tcl.h >> nmakehlp.out]
+!error *** Could not locate Tcl source directory.
+!endif
+!include nmakehlp.out
+TCLINSTALL = 0
+TCLDIR = $(_TCLDIR)
+_TCL_H = $(_TCLDIR)\generic\tcl.h
+
+!endif # exist(...) && !$(NEED_TCL_SOURCE)
+
+!endif # TCLDIR
+
+!ifndef _TCL_H
+MSG =^
+Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h.
+!error $(MSG)
+!endif
+
+# Now do the same to locate Tk headers and libs if project requires Tk
+!if $(NEED_TK)
+
+!if "$(TKDIR)" != ""
+
+_TKDIR = $(TKDIR:/=\)
+!if exist("$(_TKDIR)\include\tk.h")
+TKINSTALL = 1
+_TK_H = $(_TKDIR)\include\tk.h
+!elseif exist("$(_TKDIR)\generic\tk.h")
+TKINSTALL = 0
+_TK_H = $(_TKDIR)\generic\tk.h
+!endif
+
+!else # TKDIR not defined
+
+# Need to locate Tcl depending on whether it needs Tcl source or not.
+# If we don't, check the INSTALLDIR for an installed Tcl first
+
+!if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
+
+TKINSTALL = 1
+# NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions
+# later so the \.. accounts for the /lib
+_TKDIR = $(_INSTALLDIR)\..
+_TK_H = $(_TKDIR)\include\tk.h
+TKDIR = $(_TKDIR)
+
+!else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
+
+!if [echo _TKDIR = \> nmakehlp.out] \
+ || [nmakehlp -L generic\tk.h >> nmakehlp.out]
+!error *** Could not locate Tk source directory.
+!endif
+!include nmakehlp.out
+TKINSTALL = 0
+TKDIR = $(_TKDIR)
+_TK_H = $(_TKDIR)\generic\tk.h
+
+!endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE)
+
+!endif # TKDIR
+
+!ifndef _TK_H
+MSG =^
+Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h.
+!error $(MSG)
+!endif
+
+!endif # NEED_TK
+
+!if $(NEED_TCL_SOURCE) && $(TCLINSTALL)
+MSG = ^
+*** Warning: This extension requires the source distribution of Tcl.^
+*** Please set the TCLDIR macro to point to the Tcl sources.
+!error $(MSG)
+!endif
+
+!if $(NEED_TK_SOURCE)
+!if $(TKINSTALL)
+MSG = ^
+*** Warning: This extension requires the source distribution of Tk.^
+*** Please set the TKDIR macro to point to the Tk sources.
+!error $(MSG)
+!endif
+!endif
+
+
+# If INSTALLDIR set to Tcl installation root dir then reset to the
+# lib dir for installing extensions
+!if exist("$(_INSTALLDIR)\include\tcl.h")
+_INSTALLDIR=$(_INSTALLDIR)\lib
+!endif
+
+# END Case 2(c) or (d) - Building an extension
+!endif # if $(DOING_TCL)
+
+################################################################
+# 3. Determine compiler version and architecture
+# In this section, we figure out the compiler version and the
+# architecture for which we are building. This sets the
+# following macros:
+# VCVERSION - the internal compiler version as 1200, 1400, 1910 etc.
+# This is also printed by the compiler in dotted form 19.10 etc.
+# VCVER - the "marketing version", for example Visual C++ 6 for internal
+# compiler version 1200. This is kept only for legacy reasons as it
+# does not make sense for recent Microsoft compilers. Only used for
+# output directory names.
+# ARCH - set to IX86, ARM64 or AMD64 depending on 32- or 64-bit target
+# NATIVE_ARCH - set to IX86, ARM64 or AMD64 for the host machine
+# MACHINE - same as $(ARCH) - legacy
+# _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed
+
+cc32 = $(CC) # built-in default.
+link32 = link
+lib32 = lib
+rc32 = $(RC) # built-in default.
+
+#----------------------------------------------------------------
+# Figure out the compiler architecture and version by writing
+# the C macros to a file, preprocessing them with the C
+# preprocessor and reading back the created file
_HASH=^#
_VC_MANIFEST_EMBED_EXE=
@@ -65,19 +436,70 @@ VCVER=0
&& ![echo ARCH=IX86 >> vercl.x] \
&& ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \
&& ![echo ARCH=AMD64 >> vercl.x] \
+ && ![echo $(_HASH)elif defined(_M_ARM64) >> vercl.x] \
+ && ![echo ARCH=ARM64 >> vercl.x] \
&& ![echo $(_HASH)endif >> vercl.x] \
- && ![cl -nologo -TC -P vercl.x $(ERRNULL)]
+ && ![$(cc32) -nologo -TC -P vercl.x 2>NUL]
!include vercl.i
+!if $(VCVERSION) < 1900
!if ![echo VCVER= ^\> vercl.vc] \
&& ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc]
!include vercl.vc
!endif
+!else
+# The simple calculation above does not apply to new Visual Studio releases
+# Keep the compiler version in its native form.
+VCVER = $(VCVERSION)
+!endif
!endif
-!if ![del $(ERRNUL) /q/f vercl.x vercl.i vercl.vc]
+
+!if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc]
!endif
+#----------------------------------------------------------------
+# The MACHINE macro is used by legacy makefiles so set it as well
+!ifdef MACHINE
+!if "$(MACHINE)" == "x86"
+!undef MACHINE
+MACHINE = IX86
+!elseif "$(MACHINE)" == "arm64"
+!undef MACHINE
+MACHINE = ARM64
+!elseif "$(MACHINE)" == "x64"
+!undef MACHINE
+MACHINE = AMD64
+!endif
+!if "$(MACHINE)" != "$(ARCH)"
+!error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH).
+!endif
+!else
+MACHINE=$(ARCH)
+!endif
+
+#---------------------------------------------------------------
+# The PLATFORM_IDENTIFY macro matches the values returned by
+# the Tcl platform::identify command
+!if "$(MACHINE)" == "AMD64"
+PLATFORM_IDENTIFY = win32-x86_64
+!elseif "$(MACHINE)" == "ARM64"
+PLATFORM_IDENTIFY = win32-arm
+!else
+PLATFORM_IDENTIFY = win32-ix86
+!endif
+
+# The MULTIPLATFORM macro controls whether binary extensions are installed
+# in platform-specific directories. Intended to be set/used by extensions.
+!ifndef MULTIPLATFORM_INSTALL
+MULTIPLATFORM_INSTALL = 0
+!endif
+
+#------------------------------------------------------------
+# Figure out the *host* architecture by reading the registry
+
!if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86]
NATIVE_ARCH=IX86
+!elseif ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i ARM | findstr /i 64-bit]
+NATIVE_ARCH=ARM64
!else
NATIVE_ARCH=AMD64
!endif
@@ -88,185 +510,408 @@ _VC_MANIFEST_EMBED_EXE=if exist $@.manifest mt -nologo -manifest $@.manifest -ou
_VC_MANIFEST_EMBED_DLL=if exist $@.manifest mt -nologo -manifest $@.manifest -outputresource:$@;2
!endif
-!ifndef MACHINE
-MACHINE=$(ARCH)
-!endif
-
-!ifndef CFG_ENCODING
-CFG_ENCODING = \"cp1252\"
-!endif
-
-!message ===============================================================================
+################################################################
+# 4. Build the nmakehlp program
+# This is a helper app we need to overcome nmake's limiting
+# environment. We will call out to it to get various bits of
+# information about supported compiler options etc.
+#
+# Tcl itself will always use the nmakehlp.c program which is
+# in its own source. It will be kept updated there.
+#
+# Extensions built against an installed Tcl will use the installed
+# copy of Tcl's nmakehlp.c if there is one and their own version
+# otherwise. In the latter case, they would also be using their own
+# rules.vc. Note that older versions of Tcl do not install nmakehlp.c
+# or rules.vc.
+#
+# Extensions built against Tcl sources will use the one from the Tcl source.
+#
+# When building an extension using a sufficiently new version of Tcl,
+# rules-ext.vc will define NMAKEHLPC appropriately to point to the
+# copy of nmakehlp.c to be used.
-#----------------------------------------------------------
-# build the helper app we need to overcome nmake's limiting
-# environment.
-#----------------------------------------------------------
+!ifndef NMAKEHLPC
+# Default to the one in the current directory (the extension's own nmakehlp.c)
+NMAKEHLPC = nmakehlp.c
-!if !exist(nmakehlp.exe)
-!if [$(cc32) -nologo nmakehlp.c -link -subsystem:console > nul]
+!if !$(DOING_TCL)
+!if $(TCLINSTALL)
+!if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c")
+NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c
!endif
+!else # !$(TCLINSTALL)
+!if exist("$(_TCLDIR)\win\nmakehlp.c")
+NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c
!endif
+!endif # $(TCLINSTALL)
+!endif # !$(DOING_TCL)
-#----------------------------------------------------------
-# Test for compiler features
-#----------------------------------------------------------
+!endif # NMAKEHLPC
-### test for optimizations
-!if [nmakehlp -c -Ot]
-!message *** Compiler has 'Optimizations'
-OPTIMIZING = 1
+# We always build nmakehlp even if it exists since we do not know
+# what source it was built from.
+!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
+!if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul]
+!endif
!else
-!message *** Compiler does not have 'Optimizations'
-OPTIMIZING = 0
+!if [copy $(NMAKEHLPC:nmakehlp.c=x86_64-w64-mingw32-nmakehlp.exe) nmakehlp.exe >NUL]
!endif
-
-OPTIMIZATIONS =
-
-!if [nmakehlp -c -Ot]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Ot
!endif
-!if [nmakehlp -c -Oi]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Oi
-!endif
+################################################################
+# 5. Test for compiler features
+# Visual C++ compiler options have changed over the years. Check
+# which options are supported by the compiler in use.
+#
+# The following macros are set:
+# OPTIMIZATIONS - the compiler flags to be used for optimized builds
+# DEBUGFLAGS - the compiler flags to be used for debug builds
+# LINKERFLAGS - Flags passed to the linker
+#
+# Note that these are the compiler settings *available*, not those
+# that will be *used*. The latter depends on the OPTS macro settings
+# which we have not yet parsed.
+#
+# Also note that some of the flags in OPTIMIZATIONS are not really
+# related to optimization. They are placed there only for legacy reasons
+# as some extensions expect them to be included in that macro.
+# -Op improves float consistency. Note only needed for older compilers
+# Newer compilers do not need or support this option.
!if [nmakehlp -c -Op]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Op
+FPOPTS = -Op
!endif
+# Strict floating point semantics - present in newer compilers in lieu of -Op
!if [nmakehlp -c -fp:strict]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -fp:strict
+FPOPTS = $(FPOPTS) -fp:strict
+!endif
+
+!if "$(MACHINE)" == "IX86"
+### test for pentium errata
+!if [nmakehlp -c -QI0f]
+!message *** Compiler has 'Pentium 0x0f fix'
+FPOPTS = $(FPOPTS) -QI0f
+!else
+!message *** Compiler does not have 'Pentium 0x0f fix'
+!endif
!endif
-!if [nmakehlp -c -Gs]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -Gs
+### test for optimizations
+# /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per
+# documentation. Note we do NOT want /Gs as that inserts a _chkstk
+# stack probe at *every* function entry, not just those with more than
+# a page of stack allocation resulting in a performance hit. However,
+# /O2 documentation is misleading as its stack probes are simply the
+# default page size locals allocation probes and not what is implied
+# by an explicit /Gs option.
+
+OPTIMIZATIONS = $(FPOPTS)
+
+!if [nmakehlp -c -O2]
+OPTIMIZING = 1
+OPTIMIZATIONS = $(OPTIMIZATIONS) -O2
+!else
+# Legacy, really. All modern compilers support this
+!message *** Compiler does not have 'Optimizations'
+OPTIMIZING = 0
!endif
+# Checks for buffer overflows in local arrays
!if [nmakehlp -c -GS]
OPTIMIZATIONS = $(OPTIMIZATIONS) -GS
!endif
+# Link time optimization. Note that this option (potentially) makes
+# generated libraries only usable by the specific VC++ version that
+# created it. Requires /LTCG linker option
!if [nmakehlp -c -GL]
OPTIMIZATIONS = $(OPTIMIZATIONS) -GL
+CC_GL_OPT_ENABLED = 1
+!else
+# In newer compilers -GL and -YX are incompatible.
+!if [nmakehlp -c -YX]
+OPTIMIZATIONS = $(OPTIMIZATIONS) -YX
!endif
+!endif # [nmakehlp -c -GL]
-DEBUGFLAGS =
+DEBUGFLAGS = $(FPOPTS)
+# Run time error checks. Not available or valid in a release, non-debug build
+# RTC is for modern compilers, -GZ is legacy
!if [nmakehlp -c -RTC1]
DEBUGFLAGS = $(DEBUGFLAGS) -RTC1
!elseif [nmakehlp -c -GZ]
DEBUGFLAGS = $(DEBUGFLAGS) -GZ
!endif
-COMPILERFLAGS =-W3 -DUNICODE -D_UNICODE
+#----------------------------------------------------------------
+# Linker flags
-# In v13 -GL and -YX are incompatible.
-!if [nmakehlp -c -YX]
-!if ![nmakehlp -c -GL]
-OPTIMIZATIONS = $(OPTIMIZATIONS) -YX
-!endif
+# LINKER_TESTFLAGS are for internal use when we call nmakehlp to test
+# if the linker supports a specific option. Without these flags link will
+# return "LNK1561: entry point must be defined" error compiling from VS-IDE:
+# They are not passed through to the actual application / extension
+# link rules.
+!ifndef LINKER_TESTFLAGS
+LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out
!endif
-!if "$(MACHINE)" == "IX86"
-### test for pentium errata
-!if [nmakehlp -c -QI0f]
-!message *** Compiler has 'Pentium 0x0f fix'
-COMPILERFLAGS = $(COMPILERFLAGS) -QI0f
-!else
-!message *** Compiler does not have 'Pentium 0x0f fix'
+LINKERFLAGS =
+
+# If compiler has enabled link time optimization, linker must too with -ltcg
+!ifdef CC_GL_OPT_ENABLED
+!if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)]
+LINKERFLAGS = $(LINKERFLAGS) -ltcg
+!endif
+!endif
+
+
+################################################################
+# 6. Extract various version numbers from headers
+# For Tcl and Tk, version numbers are extracted from tcl.h and tk.h
+# respectively. For extensions, versions are extracted from the
+# configure.in or configure.ac from the TEA configuration if it
+# exists, and unset otherwise.
+# Sets the following macros:
+# TCL_MAJOR_VERSION
+# TCL_MINOR_VERSION
+# TCL_RELEASE_SERIAL
+# TCL_PATCH_LEVEL
+# TCL_PATCH_LETTER
+# TCL_VERSION
+# TK_MAJOR_VERSION
+# TK_MINOR_VERSION
+# TK_RELEASE_SERIAL
+# TK_PATCH_LEVEL
+# TK_PATCH_LETTER
+# TK_VERSION
+# DOTVERSION - set as (for example) 2.5
+# VERSION - set as (for example 25)
+#--------------------------------------------------------------
+
+!if [echo REM = This file is generated from rules.vc > versions.vc]
!endif
+!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" "define TCL_MAJOR_VERSION" >> versions.vc]
+!endif
+!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
+!endif
+!if [echo TCL_RELEASE_SERIAL = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_RELEASE_SERIAL >> versions.vc]
+!endif
+!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
+ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
!endif
-!if "$(MACHINE)" == "IA64"
-### test for Itanium errata
-!if [nmakehlp -c -QIA64_Bx]
-!message *** Compiler has 'B-stepping errata workarounds'
-COMPILERFLAGS = $(COMPILERFLAGS) -QIA64_Bx
-!else
-!message *** Compiler does not have 'B-stepping errata workarounds'
+!if defined(_TK_H)
+!if [echo TK_MAJOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) "define TK_MAJOR_VERSION" >> versions.vc]
+!endif
+!if [echo TK_MINOR_VERSION = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc]
!endif
+!if [echo TK_RELEASE_SERIAL = \>> versions.vc] \
+ && [nmakehlp -V "$(_TK_H)" TK_RELEASE_SERIAL >> versions.vc]
!endif
+!if [echo TK_PATCH_LEVEL = \>> versions.vc] \
+ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc]
+!endif
+!endif # _TK_H
-!if "$(MACHINE)" == "IX86"
-### test for -align:4096, when align:512 will do.
-!if [nmakehlp -l -opt:nowin98]
-!message *** Linker has 'Win98 alignment problem'
-ALIGN98_HACK = 1
+!include versions.vc
+
+TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
+TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
+!if [nmakehlp -f $(TCL_PATCH_LEVEL) "a"]
+TCL_PATCH_LETTER = a
+!elseif [nmakehlp -f $(TCL_PATCH_LEVEL) "b"]
+TCL_PATCH_LETTER = b
!else
-!message *** Linker does not have 'Win98 alignment problem'
-ALIGN98_HACK = 0
+TCL_PATCH_LETTER = .
!endif
+
+!if defined(_TK_H)
+
+TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION)
+TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
+!if [nmakehlp -f $(TK_PATCH_LEVEL) "a"]
+TK_PATCH_LETTER = a
+!elseif [nmakehlp -f $(TK_PATCH_LEVEL) "b"]
+TK_PATCH_LETTER = b
!else
-ALIGN98_HACK = 0
+TK_PATCH_LETTER = .
!endif
-LINKERFLAGS =
-
-!if [nmakehlp -l -ltcg]
-LINKERFLAGS =-ltcg
!endif
-#----------------------------------------------------------
-# Decode the options requested.
-#----------------------------------------------------------
+# Set DOTVERSION and VERSION
+!if $(DOING_TCL)
+
+DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
+VERSION = $(TCL_VERSION)
+
+!elseif $(DOING_TK)
-!if "$(OPTS)" == "" || [nmakehlp -f "$(OPTS)" "none"]
+DOTVERSION = $(TK_DOTVERSION)
+VERSION = $(TK_VERSION)
+
+!else # Doing a non-Tk extension
+
+# If parent makefile has not defined DOTVERSION, try to get it from TEA
+# first from a configure.in file, and then from configure.ac
+!ifndef DOTVERSION
+!if [echo DOTVERSION = \> versions.vc] \
+ || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc]
+!if [echo DOTVERSION = \> versions.vc] \
+ || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc]
+!error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc.
+!endif
+!endif
+!include versions.vc
+!endif # DOTVERSION
+VERSION = $(DOTVERSION:.=)
+
+!endif # $(DOING_TCL) ... etc.
+
+# Windows RC files have 3 version components. Ensure this irrespective
+# of how many components the package has specified. Basically, ensure
+# minimum 4 components by appending 4 0's and then pick out the first 4.
+# Also take care of the fact that DOTVERSION may have "a" or "b" instead
+# of "." separating the version components.
+DOTSEPARATED=$(DOTVERSION:a=.)
+DOTSEPARATED=$(DOTSEPARATED:b=.)
+!if [echo RCCOMMAVERSION = \> versions.vc] \
+ || [for /f "tokens=1,2,3,4,5* delims=." %a in ("$(DOTSEPARATED).0.0.0.0") do echo %a,%b,%c,%d >> versions.vc]
+!error *** Could not generate RCCOMMAVERSION ***
+!endif
+!include versions.vc
+
+########################################################################
+# 7. Parse the OPTS macro to work out the requested build configuration.
+# Based on this, we will construct the actual switches to be passed to the
+# compiler and linker using the macros defined in the previous section.
+# The following macros are defined by this section based on OPTS
+# STATIC_BUILD - 0 -> Tcl is to be built as a shared library
+# 1 -> build as a static library and shell
+# TCL_THREADS - legacy but always 1 on Windows since winsock requires it.
+# DEBUG - 1 -> debug build, 0 -> release builds
+# SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's
+# PROFILE - 1 -> generate profiling info, 0 -> no profiling
+# PGO - 1 -> profile based optimization, 0 -> no
+# MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build
+# 0 -> link to static C runtime for static Tcl build.
+# Does not impact shared Tcl builds (STATIC_BUILD == 0)
+# Default: 1 for Tcl 8.7 and up, 0 otherwise.
+# TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions
+# in the Tcl and Wish shell. 0 -> keep them as shared libraries. Does
+# not impact shared Tcl builds. Implied by STATIC_BUILD since Tcl 8.7.
+# USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation.
+# 0 -> Use the non-thread allocator.
+# UNCHECKED - 1 -> when doing a debug build with symbols, use the release
+# C runtime, 0 -> use the debug C runtime.
+# USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking
+# CONFIG_CHECK - 1 -> check current build configuration against Tcl
+# configuration (ignored for Tcl itself)
+# _USE_64BIT_TIME_T - forces a build using 64-bit time_t for 32-bit build
+# (CRT library should support this, not needed for Tcl 9.x)
+# Further, LINKERFLAGS are modified based on above.
+
+# Default values for all the above
STATIC_BUILD = 0
TCL_THREADS = 1
DEBUG = 0
SYMBOLS = 0
PROFILE = 0
PGO = 0
-MSVCRT = 0
-LOIMPACT = 0
+MSVCRT = 1
TCL_USE_STATIC_PACKAGES = 0
USE_THREAD_ALLOC = 1
UNCHECKED = 0
+CONFIG_CHECK = 1
+!if $(DOING_TCL)
+USE_STUBS = 0
!else
+USE_STUBS = 1
+!endif
+
+# If OPTS is not empty AND does not contain "none" which turns off all OPTS
+# set the above macros based on OPTS content
+!if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"]
+
+# OPTS are specified, parse them
+
!if [nmakehlp -f $(OPTS) "static"]
!message *** Doing static
STATIC_BUILD = 1
-!else
-STATIC_BUILD = 0
!endif
+
+!if [nmakehlp -f $(OPTS) "nostubs"]
+!message *** Not using stubs
+USE_STUBS = 0
+!endif
+
+!if [nmakehlp -f $(OPTS) "nomsvcrt"]
+!message *** Doing nomsvcrt
+MSVCRT = 0
+!else
!if [nmakehlp -f $(OPTS) "msvcrt"]
!message *** Doing msvcrt
-MSVCRT = 1
!else
+!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7 && $(STATIC_BUILD)
MSVCRT = 0
!endif
-!if [nmakehlp -f $(OPTS) "staticpkg"]
+!endif
+!endif # [nmakehlp -f $(OPTS) "nomsvcrt"]
+
+!if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD)
!message *** Doing staticpkg
TCL_USE_STATIC_PACKAGES = 1
-!else
-TCL_USE_STATIC_PACKAGES = 0
!endif
+
!if [nmakehlp -f $(OPTS) "nothreads"]
!message *** Compile explicitly for non-threaded tcl
-TCL_THREADS = 0
-!else
-TCL_THREADS = 1
-USE_THREAD_ALLOC= 1
+TCL_THREADS = 0
+USE_THREAD_ALLOC= 0
+!endif
+
+!if [nmakehlp -f $(OPTS) "tcl8"]
+!message *** Build for Tcl8
+TCL_BUILD_FOR = 8
+!endif
+
+!if $(TCL_MAJOR_VERSION) == 8
+!if [nmakehlp -f $(OPTS) "time64bit"]
+!message *** Force 64-bit time_t
+_USE_64BIT_TIME_T = 1
+!endif
!endif
+
+# Yes, it's weird that the "symbols" option controls DEBUG and
+# the "pdbs" option controls SYMBOLS. That's historical.
!if [nmakehlp -f $(OPTS) "symbols"]
!message *** Doing symbols
DEBUG = 1
!else
DEBUG = 0
!endif
+
!if [nmakehlp -f $(OPTS) "pdbs"]
!message *** Doing pdbs
SYMBOLS = 1
!else
SYMBOLS = 0
!endif
+
!if [nmakehlp -f $(OPTS) "profile"]
!message *** Doing profile
PROFILE = 1
!else
PROFILE = 0
!endif
+
!if [nmakehlp -f $(OPTS) "pgi"]
!message *** Doing profile guided optimization instrumentation
PGO = 1
@@ -276,53 +921,149 @@ PGO = 2
!else
PGO = 0
!endif
+
!if [nmakehlp -f $(OPTS) "loimpact"]
-!message *** Doing loimpact
-LOIMPACT = 1
-!else
-LOIMPACT = 0
+!message *** Warning: ignoring option "loimpact" - deprecated on modern Windows.
!endif
+
+# TBD - should get rid of this option
!if [nmakehlp -f $(OPTS) "thrdalloc"]
!message *** Doing thrdalloc
USE_THREAD_ALLOC = 1
!endif
+
!if [nmakehlp -f $(OPTS) "tclalloc"]
-!message *** Doing tclalloc
USE_THREAD_ALLOC = 0
!endif
-!if [nmakehlp -f $(OPTS) "unchecked"]
-!message *** Doing unchecked
-UNCHECKED = 1
-!else
-UNCHECKED = 0
+
+!if [nmakehlp -f $(OPTS) "unchecked"]
+!message *** Doing unchecked
+UNCHECKED = 1
+!else
+UNCHECKED = 0
+!endif
+
+!if [nmakehlp -f $(OPTS) "noconfigcheck"]
+CONFIG_CHECK = 1
+!else
+CONFIG_CHECK = 0
+!endif
+
+!endif # "$(OPTS)" != "" && ... parsing of OPTS
+
+# Set linker flags based on above
+
+!if $(PGO) > 1
+!if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)]
+LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize
+!else
+MSG=^
+This compiler does not support profile guided optimization.
+!error $(MSG)
+!endif
+!elseif $(PGO) > 0
+!if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)]
+LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument
+!else
+MSG=^
+This compiler does not support profile guided optimization.
+!error $(MSG)
+!endif
+!endif
+
+################################################################
+# 8. Parse the STATS macro to configure code instrumentation
+# The following macros are set by this section:
+# TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation
+# 0 -> disables
+# TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging
+# 0 -> disables
+
+# Default both are off
+TCL_MEM_DEBUG = 0
+TCL_COMPILE_DEBUG = 0
+
+!if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"]
+
+!if [nmakehlp -f $(STATS) "memdbg"]
+!message *** Doing memdbg
+TCL_MEM_DEBUG = 1
+!else
+TCL_MEM_DEBUG = 0
+!endif
+
+!if [nmakehlp -f $(STATS) "compdbg"]
+!message *** Doing compdbg
+TCL_COMPILE_DEBUG = 1
+!else
+TCL_COMPILE_DEBUG = 0
+!endif
+
+!endif
+
+####################################################################
+# 9. Parse the CHECKS macro to configure additional compiler checks
+# The following macros are set by this section:
+# WARNINGS - compiler switches that control the warnings level
+# TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions
+# 0 -> enable deprecated functions
+
+# Defaults - Permit deprecated functions and warning level 3
+TCL_NO_DEPRECATED = 0
+WARNINGS = -W3
+
+!if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"]
+
+!if [nmakehlp -f $(CHECKS) "nodep"]
+!message *** Doing nodep check
+TCL_NO_DEPRECATED = 1
+!endif
+
+!if [nmakehlp -f $(CHECKS) "fullwarn"]
+!message *** Doing full warnings check
+WARNINGS = -W4
+!if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)]
+LINKERFLAGS = $(LINKERFLAGS) -warn:3
!endif
!endif
+!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64]
+!message *** Doing 64bit portability warnings
+WARNINGS = $(WARNINGS) -Wp64
+!endif
-!if !$(STATIC_BUILD)
-# Make sure we don't build overly fat DLLs.
-MSVCRT = 1
-# We shouldn't statically put the extensions inside the shell when dynamic.
-TCL_USE_STATIC_PACKAGES = 0
!endif
-#----------------------------------------------------------
+################################################################
+# 10. Construct output directory and file paths
# Figure-out how to name our intermediate and output directories.
-# We wouldn't want different builds to use the same .obj files
-# by accident.
-#----------------------------------------------------------
+# In order to avoid inadvertent mixing of object files built using
+# different compilers, build configurations etc.,
+#
+# Naming convention (suffixes):
+# t = full thread support. (Not used for Tcl >= 8.7)
+# s = static library (as opposed to an import library)
+# g = linked to the debug enabled C run-time.
+# x = special static build when it links to the dynamic C run-time.
+#
+# The following macros are set in this section:
+# SUFX - the suffix to use for binaries based on above naming convention
+# BUILDDIRTOP - the toplevel default output directory
+# is of the form {Release,Debug}[_AMD64][_COMPILERVERSION]
+# TMP_DIR - directory where object files are created
+# OUT_DIR - directory where output executables are created
+# Both TMP_DIR and OUT_DIR are defaulted only if not defined by the
+# parent makefile (or command line). The default values are
+# based on BUILDDIRTOP.
+# STUBPREFIX - name of the stubs library for this project
+# PRJIMPLIB - output path of the generated project import library
+# PRJLIBNAME - name of generated project library
+# PRJLIB - output path of generated project library
+# PRJSTUBLIBNAME - name of the generated project stubs library
+# PRJSTUBLIB - output path of the generated project stubs library
+# RESFILE - output resource file (only if not static build)
-#----------------------------------------
-# Naming convention:
-# t = full thread support.
-# s = static library (as opposed to an
-# import library)
-# g = linked to the debug enabled C
-# run-time.
-# x = special static build when it
-# links to the dynamic C run-time.
-#----------------------------------------
SUFX = tsgx
!if $(DEBUG)
@@ -338,7 +1079,7 @@ BUILDDIRTOP =$(BUILDDIRTOP)_$(MACHINE)
BUILDDIRTOP =$(BUILDDIRTOP)_VC$(VCVER)
!endif
-!if !$(DEBUG) || $(DEBUG) && $(UNCHECKED)
+!if !$(DEBUG) || $(TCL_VERSION) > 86 || $(DEBUG) && $(UNCHECKED)
SUFX = $(SUFX:g=)
!endif
@@ -348,20 +1089,18 @@ TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX
TMP_DIRFULL = $(TMP_DIRFULL:Static=)
SUFX = $(SUFX:s=)
EXT = dll
-!if $(MSVCRT)
TMP_DIRFULL = $(TMP_DIRFULL:X=)
SUFX = $(SUFX:x=)
-!endif
!else
TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=)
EXT = lib
-!if !$(MSVCRT)
+!if $(MSVCRT) && $(TCL_VERSION) > 86 || !$(MSVCRT) && $(TCL_VERSION) < 87
TMP_DIRFULL = $(TMP_DIRFULL:X=)
SUFX = $(SUFX:x=)
!endif
!endif
-!if !$(TCL_THREADS)
+!if !$(TCL_THREADS) || $(TCL_VERSION) > 86
TMP_DIRFULL = $(TMP_DIRFULL:Threaded=)
SUFX = $(SUFX:t=)
!endif
@@ -377,335 +1116,798 @@ OUT_DIR = $(TMP_DIR)
!endif
!endif
+# Relative paths -> absolute
+!if [echo OUT_DIR = \> nmakehlp.out] \
+ || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out]
+!error *** Could not fully qualify path OUT_DIR=$(OUT_DIR)
+!endif
+!if [echo TMP_DIR = \>> nmakehlp.out] \
+ || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out]
+!error *** Could not fully qualify path TMP_DIR=$(TMP_DIR)
+!endif
+!include nmakehlp.out
-#----------------------------------------------------------
-# Decode the statistics requested.
-#----------------------------------------------------------
+# The name of the stubs library for the project being built
+STUBPREFIX = $(PROJECT)stub
-!if "$(STATS)" == "" || [nmakehlp -f "$(STATS)" "none"]
-TCL_MEM_DEBUG = 0
-TCL_COMPILE_DEBUG = 0
-!else
-!if [nmakehlp -f $(STATS) "memdbg"]
-!message *** Doing memdbg
-TCL_MEM_DEBUG = 1
+#
+# Set up paths to various Tcl executables and libraries needed by extensions
+#
+
+# TIP 430. Unused for 8.6 but no harm defining it to allow a common rules.vc
+TCL_ZIP_FILE = libtcl$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)$(TCL_PATCH_LETTER)$(TCL_RELEASE_SERIAL).zip
+TK_ZIP_FILE = libtk$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)$(TK_PATCH_LETTER)$(TK_RELEASE_SERIAL).zip
+
+!if $(DOING_TCL)
+TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe
+TCLSH = $(OUT_DIR)\$(TCLSHNAME)
+TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
+TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
+TCLLIB = $(OUT_DIR)\$(TCLLIBNAME)
+TCLSCRIPTZIP = $(OUT_DIR)\$(TCL_ZIP_FILE)
+
+!if $(TCL_MAJOR_VERSION) == 8
+TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
!else
-TCL_MEM_DEBUG = 0
+TCLSTUBLIBNAME = $(STUBPREFIX).lib
!endif
-!if [nmakehlp -f $(STATS) "compdbg"]
-!message *** Doing compdbg
-TCL_COMPILE_DEBUG = 1
+TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME)
+TCL_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)"
+
+!else # !$(DOING_TCL)
+
+!if $(TCLINSTALL) # Building against an installed Tcl
+
+# When building extensions, we need to locate tclsh. Depending on version
+# of Tcl we are building against, this may or may not have a "t" suffix.
+# Try various possibilities in turn.
+TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe
+!if !exist("$(TCLSH)")
+TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
+!endif
+
+!if $(TCL_MAJOR_VERSION) == 8
+TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib
!else
-TCL_COMPILE_DEBUG = 0
+TCLSTUBLIB = $(_TCLDIR)\lib\tclstub.lib
!endif
+TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib
+# When building extensions, may be linking against Tcl that does not add
+# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
+!if !exist("$(TCLIMPLIB)")
+TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)t$(SUFX:t=).lib
!endif
+TCL_LIBRARY = $(_TCLDIR)\lib
+TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib
+TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib
+TCLSCRIPTZIP = $(_TCLDIR)\lib\$(TCL_ZIP_FILE)
+TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target
+TCL_INCLUDES = -I"$(_TCLDIR)\include"
+!else # Building against Tcl sources
-#----------------------------------------------------------
-# Decode the checks requested.
-#----------------------------------------------------------
-
-!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"]
-TCL_NO_DEPRECATED = 0
-WARNINGS = -W3
-!else
-!if [nmakehlp -f $(CHECKS) "nodep"]
-!message *** Doing nodep check
-TCL_NO_DEPRECATED = 1
+TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe
+!if !exist($(TCLSH))
+TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX:t=).exe
+!endif
+!if $(TCL_MAJOR_VERSION) == 8
+TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib
!else
-TCL_NO_DEPRECATED = 0
+TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub.lib
!endif
-!if [nmakehlp -f $(CHECKS) "fullwarn"]
-!message *** Doing full warnings check
-WARNINGS = -W4
-!if [nmakehlp -l -warn:3]
-LINKERFLAGS = $(LINKERFLAGS) -warn:3
+TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib
+# When building extensions, may be linking against Tcl that does not add
+# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
+!if !exist("$(TCLIMPLIB)")
+TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)t$(SUFX:t=).lib
!endif
+TCL_LIBRARY = $(_TCLDIR)\library
+TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib
+TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib
+TCLSCRIPTZIP = $(_TCLDIR)\win\$(BUILDDIRTOP)\$(TCL_ZIP_FILE)
+TCLTOOLSDIR = $(_TCLDIR)\tools
+TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win"
+
+!endif # TCLINSTALL
+
+!if !$(STATIC_BUILD) && "$(TCL_BUILD_FOR)" == "8"
+tcllibs = "$(TCLSTUBLIB)"
!else
-WARNINGS = -W3
+tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)"
!endif
-!if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64]
-!message *** Doing 64bit portability warnings
-WARNINGS = $(WARNINGS) -Wp64
+
+!endif # $(DOING_TCL)
+
+# We need a tclsh that will run on the host machine as part of the build.
+# IX86 runs on all architectures.
+!ifndef TCLSH_NATIVE
+!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)"
+TCLSH_NATIVE = $(TCLSH)
+!else
+!error You must explicitly set TCLSH_NATIVE for cross-compilation
!endif
!endif
-!if $(PGO) > 1
-!if [nmakehlp -l -ltcg:pgoptimize]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize
+# Do the same for Tk and Tk extensions that require the Tk libraries
+!if $(DOING_TK) || $(NEED_TK)
+WISHNAMEPREFIX = wish
+WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe
+TKLIBNAME8 = tk$(TK_VERSION)$(SUFX).$(EXT)
+TKLIBNAME9 = tcl9tk$(TK_VERSION)$(SUFX).$(EXT)
+!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
+TKLIBNAME = tk$(TK_VERSION)$(SUFX).$(EXT)
+TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib
!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
+TKLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).$(EXT)
+TKIMPLIBNAME = tcl9tk$(TK_VERSION)$(SUFX).lib
!endif
-!elseif $(PGO) > 0
-!if [nmakehlp -l -ltcg:pginstrument]
-LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument
+!if $(TK_MAJOR_VERSION) == 8
+TKSTUBLIBNAME = tkstub$(TK_VERSION).lib
!else
-MSG=^
-This compiler does not support profile guided optimization.
-!error $(MSG)
+TKSTUBLIBNAME = tkstub.lib
!endif
+
+!if $(DOING_TK)
+WISH = $(OUT_DIR)\$(WISHNAME)
+TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME)
+TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME)
+TKLIB = $(OUT_DIR)\$(TKLIBNAME)
+TK_INCLUDES = -I"$(WIN_DIR)" -I"$(GENERICDIR)"
+TKSCRIPTZIP = $(OUT_DIR)\$(TK_ZIP_FILE)
+
+!else # effectively NEED_TK
+
+!if $(TKINSTALL) # Building against installed Tk
+WISH = $(_TKDIR)\bin\$(WISHNAME)
+TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME)
+TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME)
+# When building extensions, may be linking against Tk that does not add
+# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
+!if !exist("$(TKIMPLIB)")
+TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib
+TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME)
!endif
+TK_INCLUDES = -I"$(_TKDIR)\include"
+TKSCRIPTZIP = $(_TKDIR)\lib\$(TK_ZIP_FILE)
-#----------------------------------------------------------
-# Set our defines now armed with our options.
-#----------------------------------------------------------
+!else # Building against Tk sources
+
+WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME)
+TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME)
+TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME)
+# When building extensions, may be linking against Tk that does not add
+# "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility.
+!if !exist("$(TKIMPLIB)")
+TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib
+TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME)
+!endif
+TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
+TKSCRIPTZIP = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TK_ZIP_FILE)
+
+!endif # TKINSTALL
+
+tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)"
+
+!endif # $(DOING_TK)
+!endif # $(DOING_TK) || $(NEED_TK)
+
+# Various output paths
+PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib
+PRJLIBNAME8 = $(PROJECT)$(VERSION)$(SUFX).$(EXT)
+# Even when building against Tcl 8, PRJLIBNAME9 must not have "t"
+PRJLIBNAME9 = tcl9$(PROJECT)$(VERSION)$(SUFX:t=).$(EXT)
+!if $(TCL_MAJOR_VERSION) == 8 || "$(TCL_BUILD_FOR)" == "8"
+PRJLIBNAME = $(PRJLIBNAME8)
+!else
+PRJLIBNAME = $(PRJLIBNAME9)
+!endif
+PRJLIB = $(OUT_DIR)\$(PRJLIBNAME)
+
+!if $(TCL_MAJOR_VERSION) == 8
+PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib
+!else
+PRJSTUBLIBNAME = $(STUBPREFIX).lib
+!endif
+PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME)
-OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS
+# If extension parent makefile has not defined a resource definition file,
+# we will generate one from standard template.
+!if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD)
+!ifdef RCFILE
+RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res)
+!else
+RESFILE = $(TMP_DIR)\$(PROJECT).res
+!endif
+!endif
+
+###################################################################
+# 11. Construct the paths for the installation directories
+# The following macros get defined in this section:
+# LIB_INSTALL_DIR - where libraries should be installed
+# BIN_INSTALL_DIR - where the executables should be installed
+# DOC_INSTALL_DIR - where documentation should be installed
+# SCRIPT_INSTALL_DIR - where scripts should be installed
+# INCLUDE_INSTALL_DIR - where C include files should be installed
+# DEMO_INSTALL_DIR - where demos should be installed
+# PRJ_INSTALL_DIR - where package will be installed (not set for Tcl and Tk)
+
+!if $(DOING_TCL) || $(DOING_TK)
+LIB_INSTALL_DIR = $(_INSTALLDIR)\lib
+BIN_INSTALL_DIR = $(_INSTALLDIR)\bin
+DOC_INSTALL_DIR = $(_INSTALLDIR)\doc
+!if $(DOING_TCL)
+SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION)
+MODULE_INSTALL_DIR = $(_INSTALLDIR)\lib\tcl$(TCL_MAJOR_VERSION)
+!else # DOING_TK
+SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
+!endif
+DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos
+INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include
+
+!else # extension other than Tk
+
+PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION)
+!if $(MULTIPLATFORM_INSTALL)
+LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY)
+BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)\$(PLATFORM_IDENTIFY)
+!else
+LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR)
+BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR)
+!endif
+DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR)
+SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR)
+DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos
+INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include
+
+!endif
+
+###################################################################
+# 12. Set up actual options to be passed to the compiler and linker
+# Now we have all the information we need, set up the actual flags and
+# options that we will pass to the compiler and linker. The main
+# makefile should use these in combination with whatever other flags
+# and switches are specific to it.
+# The following macros are defined, names are for historical compatibility:
+# OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS
+# COMPILERFLAGS - /Dxxx C macro flags independent of any configuration options
+# crt - Compiler switch that selects the appropriate C runtime
+# cdebug - Compiler switches related to debug AND optimizations
+# cwarn - Compiler switches that set warning levels
+# cflags - complete compiler switches (subsumes cdebug and cwarn)
+# ldebug - Linker switches controlling debug information and optimization
+# lflags - complete linker switches (subsumes ldebug) except subsystem type
+# dlllflags - complete linker switches to build DLLs (subsumes lflags)
+# conlflags - complete linker switches for console program (subsumes lflags)
+# guilflags - complete linker switches for GUI program (subsumes lflags)
+# baselibs - minimum Windows libraries required. Parent makefile can
+# define PRJ_LIBS before including rules.rc if additional libs are needed
+
+OPTDEFINES = /DSTDC_HEADERS /DUSE_NMAKE=1
+!if $(VCVERSION) > 1600
+OPTDEFINES = $(OPTDEFINES) /DHAVE_STDINT_H=1
+!else
+OPTDEFINES = $(OPTDEFINES) /DMP_NO_STDINT=1
+!endif
+!if $(VCVERSION) >= 1800
+OPTDEFINES = $(OPTDEFINES) /DHAVE_INTTYPES_H=1 /DHAVE_STDBOOL_H=1
+!endif
!if $(TCL_MEM_DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG
+OPTDEFINES = $(OPTDEFINES) /DTCL_MEM_DEBUG
!endif
!if $(TCL_COMPILE_DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS
+OPTDEFINES = $(OPTDEFINES) /DTCL_COMPILE_DEBUG /DTCL_COMPILE_STATS
!endif
-!if $(TCL_THREADS)
-OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1
-!if $(USE_THREAD_ALLOC)
-OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
+!if $(TCL_THREADS) && $(TCL_VERSION) < 87
+OPTDEFINES = $(OPTDEFINES) /DTCL_THREADS=1
+!if $(USE_THREAD_ALLOC) && $(TCL_VERSION) < 87
+OPTDEFINES = $(OPTDEFINES) /DUSE_THREAD_ALLOC=1
!endif
!endif
!if $(STATIC_BUILD)
-OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD
+OPTDEFINES = $(OPTDEFINES) /DSTATIC_BUILD
+!elseif $(TCL_VERSION) > 86
+OPTDEFINES = $(OPTDEFINES) /DTCL_WITH_EXTERNAL_TOMMATH
+!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
+OPTDEFINES = $(OPTDEFINES) /DMP_64BIT
+!endif
!endif
!if $(TCL_NO_DEPRECATED)
-OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED
+OPTDEFINES = $(OPTDEFINES) /DTCL_NO_DEPRECATED
+!endif
+
+!if $(USE_STUBS)
+# Note we do not define USE_TCL_STUBS even when building tk since some
+# test targets in tk do not use stubs
+!if !$(DOING_TCL)
+USE_STUBS_DEFS = /DUSE_TCL_STUBS /DUSE_TCLOO_STUBS
+!if $(NEED_TK)
+USE_STUBS_DEFS = $(USE_STUBS_DEFS) /DUSE_TK_STUBS
+!endif
!endif
+!endif # USE_STUBS
!if !$(DEBUG)
-OPTDEFINES = $(OPTDEFINES) -DNDEBUG
+OPTDEFINES = $(OPTDEFINES) /DNDEBUG
!if $(OPTIMIZING)
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED
+OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_OPTIMIZED
!endif
!endif
!if $(PROFILE)
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED
+OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_PROFILED
!endif
-!if "$(MACHINE)" == "IA64" || "$(MACHINE)" == "AMD64"
-OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT
+!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
+OPTDEFINES = $(OPTDEFINES) /DTCL_CFG_DO64BIT
!endif
!if $(VCVERSION) < 1300
-OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64
+OPTDEFINES = $(OPTDEFINES) /DNO_STRTOI64=1
!endif
-#----------------------------------------------------------
-# Locate the Tcl headers to build against
-#----------------------------------------------------------
-
-!if "$(PROJECT)" == "tcl"
-
-_TCL_H = ..\generic\tcl.h
-
-!else
+!if $(TCL_MAJOR_VERSION) == 8
+!if "$(_USE_64BIT_TIME_T)" == "1"
+OPTDEFINES = $(OPTDEFINES) /D_USE_64BIT_TIME_T=1
+!endif
+!endif
+!if "$(TCL_BUILD_FOR)" == "8"
+OPTDEFINES = $(OPTDEFINES) /DTCL_MAJOR_VERSION=8
+!endif
-# If INSTALLDIR set to tcl root dir then reset to the lib dir.
-!if exist("$(_INSTALLDIR)\include\tcl.h")
-_INSTALLDIR=$(_INSTALLDIR)\lib
+# Like the TEA system only set this non empty for non-Tk extensions
+# Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME
+# so we pass both
+!if !$(DOING_TCL) && !$(DOING_TK)
+PKGNAMEFLAGS = /DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
+ /DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \
+ /DPACKAGE_VERSION="\"$(DOTVERSION)\"" \
+ /DMODULE_SCOPE=extern
!endif
-!if !defined(TCLDIR)
-!if exist("$(_INSTALLDIR)\..\include\tcl.h")
-TCLINSTALL = 1
-_TCLDIR = $(_INSTALLDIR)\..
-_TCL_H = $(_INSTALLDIR)\..\include\tcl.h
-TCLDIR = $(_INSTALLDIR)\..
+# crt picks the C run time based on selected OPTS
+!if $(MSVCRT)
+!if $(DEBUG) && !$(UNCHECKED)
+crt = -MDd
!else
-MSG=^
-Failed to find tcl.h. Set the TCLDIR macro.
-!error $(MSG)
+crt = -MD
!endif
!else
-_TCLDIR = $(TCLDIR:/=\)
-!if exist("$(_TCLDIR)\include\tcl.h")
-TCLINSTALL = 1
-_TCL_H = $(_TCLDIR)\include\tcl.h
-!elseif exist("$(_TCLDIR)\generic\tcl.h")
-TCLINSTALL = 0
-_TCL_H = $(_TCLDIR)\generic\tcl.h
+!if $(DEBUG) && !$(UNCHECKED)
+crt = -MTd
!else
-MSG =^
-Failed to find tcl.h. The TCLDIR macro does not appear correct.
-!error $(MSG)
-!endif
+crt = -MT
!endif
!endif
-#--------------------------------------------------------------
-# Extract various version numbers from tcl headers
-# The generated file is then included in the makefile.
-#--------------------------------------------------------------
+# cdebug includes compiler options for debugging as well as optimization.
+!if $(DEBUG)
-!if [echo REM = This file is generated from rules.vc > versions.vc]
-!endif
-!if [echo TCL_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc]
-!endif
-!if [echo TCL_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc]
-!endif
-!if [echo TCL_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc]
-!endif
+# In debugging mode, optimizations need to be disabled
+cdebug = -Zi -Od $(DEBUGFLAGS)
-# If building the tcl core then we need additional package versions
-!if "$(PROJECT)" == "tcl"
-!if [echo PKG_HTTP_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\http\pkgIndex.tcl http >> versions.vc]
-!endif
-!if [echo PKG_TCLTEST_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\tcltest\pkgIndex.tcl tcltest >> versions.vc]
+!else
+
+cdebug = $(OPTIMIZATIONS)
+!if $(SYMBOLS)
+cdebug = $(cdebug) -Zi
!endif
-!if [echo PKG_MSGCAT_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\msgcat\pkgIndex.tcl msgcat >> versions.vc]
+
+!endif # $(DEBUG)
+
+# cwarn includes default warning levels, also C4090 (buggy) and C4146 is useless.
+cwarn = $(WARNINGS) -wd4090 -wd4146
+
+!if "$(MACHINE)" == "AMD64" || "$(MACHINE)" == "ARM64"
+# Disable pointer<->int warnings related to cast between different sizes
+# There are a gadzillion of these due to use of ClientData and
+# clutter up compiler
+# output increasing chance of a real warning getting lost. So disable them.
+# Eventually some day, Tcl will be 64-bit clean.
+cwarn = $(cwarn) -wd4311 -wd4312
!endif
-!if [echo PKG_PLATFORM_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform " >> versions.vc]
+
+### Common compiler options that are architecture specific
+!if "$(MACHINE)" == "ARM"
+carch = /D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
+!else
+carch =
!endif
-!if [echo PKG_SHELL_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\platform\pkgIndex.tcl "platform::shell" >> versions.vc]
+
+# cpuid is only available on intel machines
+!if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "AMD64"
+carch = $(carch) /DHAVE_CPUID=1
!endif
-!if [echo PKG_DDE_VER = \>> versions.vc] \
- && [nmakehlp -V ..\library\dde\pkgIndex.tcl "dde " >> versions.vc]
+
+!if $(DEBUG)
+# Turn warnings into errors
+cwarn = $(cwarn) -WX
!endif
-!if [echo PKG_REG_VER =\>> versions.vc] \
- && [nmakehlp -V ..\library\reg\pkgIndex.tcl registry >> versions.vc]
+
+INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES)
+!if !$(DOING_TCL) && !$(DOING_TK)
+INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WIN_DIR)" -I"$(COMPATDIR)"
!endif
+
+# These flags are defined roughly in the order of the pre-reform
+# rules.vc/makefile.vc to help visually compare that the pre- and
+# post-reform build logs
+
+# cflags contains generic flags used for building practically all object files
+cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug)
+
+!if $(TCL_MAJOR_VERSION) == 8 && $(TCL_MINOR_VERSION) < 7
+cflags = $(cflags) -DTcl_Size=int
!endif
-!include versions.vc
+# appcflags contains $(cflags) and flags for building the application
+# object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus
+# flags used for building shared object files The two differ in the
+# BUILD_$(PROJECT) macro which should be defined only for the shared
+# library *implementation* and not for its caller interface
-#--------------------------------------------------------------
-# Setup tcl version dependent stuff headers
-#--------------------------------------------------------------
+appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES)
+appcflags = $(appcflags_nostubs) $(USE_STUBS_DEFS)
+pkgcflags = $(appcflags) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT)
+pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) /DBUILD_$(PROJECT)
-!if "$(PROJECT)" != "tcl"
+# stubscflags contains $(cflags) plus flags used for building a stubs
+# library for the package. Note: /DSTATIC_BUILD is defined in
+# $(OPTDEFINES) only if the OPTS configuration indicates a static
+# library. However the stubs library is ALWAYS static hence included
+# here irrespective of the OPTS setting.
+#
+# TBD - tclvfs has a comment that stubs libs should not be compiled with -GL
+# without stating why. Tcl itself compiled stubs libs with this flag.
+# so we do not remove it from cflags. -GL may prevent extensions
+# compiled with one VC version to fail to link against stubs library
+# compiled with another VC version. Check for this and fix accordingly.
+stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) /Zl /GL- /DSTATIC_BUILD $(INCLUDES) $(USE_STUBS_DEFS)
-TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION)
+# Link flags
-!if $(TCL_VERSION) < 81
-TCL_DOES_STUBS = 0
+!if $(DEBUG)
+ldebug = -debug -debugtype:cv
!else
-TCL_DOES_STUBS = 1
+ldebug = -release -opt:ref -opt:icf,3
+!if $(SYMBOLS)
+ldebug = $(ldebug) -debug -debugtype:cv
+!endif
!endif
-!if $(TCLINSTALL)
-TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
-!if !exist($(TCLSH)) && $(TCL_THREADS)
-TCLSH = "$(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe"
+# Note: Profiling is currently only possible with the Visual Studio Enterprise
+!if $(PROFILE)
+ldebug= $(ldebug) -profile
!endif
-TCLSTUBLIB = "$(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib"
-TCLIMPLIB = "$(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib"
-TCL_LIBRARY = $(_TCLDIR)\lib
-TCLREGLIB = "$(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib"
-TCLDDELIB = "$(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib"
-COFFBASE = \must\have\tcl\sources\to\build\this\target
-TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target
-TCL_INCLUDES = -I"$(_TCLDIR)\include"
-!else
-TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe"
-!if !exist($(TCLSH)) && $(TCL_THREADS)
-TCLSH = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe"
+
+### Declarations common to all linker versions
+lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug)
+
+!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
+lflags = $(lflags) -nodefaultlib:libucrt.lib
!endif
-TCLSTUBLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib"
-TCLIMPLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib"
-TCL_LIBRARY = $(_TCLDIR)\library
-TCLREGLIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib"
-TCLDDELIB = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib"
-COFFBASE = "$(_TCLDIR)\win\coffbase.txt"
-TCLTOOLSDIR = $(_TCLDIR)\tools
-TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win"
+
+dlllflags = $(lflags) -dll
+conlflags = $(lflags) -subsystem:console
+guilflags = $(lflags) -subsystem:windows
+
+# Libraries that are required for every image.
+# Extensions should define any additional libraries with $(PRJ_LIBS)
+winlibs = kernel32.lib advapi32.lib
+
+!if $(NEED_TK)
+winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib
!endif
+# Avoid 'unresolved external symbol __security_cookie' errors.
+# c.f. http://support.microsoft.com/?id=894573
+!if "$(MACHINE)" == "AMD64"
+!if $(VCVERSION) > 1399 && $(VCVERSION) < 1500
+winlibs = $(winlibs) bufferoverflowU.lib
+!endif
!endif
-#-------------------------------------------------------------------------
-# Locate the Tk headers to build against
-#-------------------------------------------------------------------------
+baselibs = $(winlibs) $(PRJ_LIBS)
-!if "$(PROJECT)" == "tk"
-_TK_H = ..\generic\tk.h
-_INSTALLDIR = $(_INSTALLDIR)\..
+!if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900
+baselibs = $(baselibs) ucrt.lib
!endif
-!ifdef PROJECT_REQUIRES_TK
-!if !defined(TKDIR)
-!if exist("$(_INSTALLDIR)\..\include\tk.h")
-TKINSTALL = 1
-_TKDIR = $(_INSTALLDIR)\..
-_TK_H = $(_TKDIR)\include\tk.h
-TKDIR = $(_TKDIR)
-!elseif exist("$(_TCLDIR)\include\tk.h")
-TKINSTALL = 1
-_TKDIR = $(_TCLDIR)
-_TK_H = $(_TKDIR)\include\tk.h
-TKDIR = $(_TKDIR)
+################################################################
+# 13. Define standard commands, common make targets and implicit rules
+
+CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\
+CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\
+CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\
+
+LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@
+DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
+
+CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
+GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs)
+RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \
+ $(TCL_INCLUDES) /DSTATIC_BUILD=$(STATIC_BUILD) \
+ /DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \
+ /DCOMMAVERSION=$(RCCOMMAVERSION) \
+ /DDOTVERSION=\"$(DOTVERSION)\" \
+ /DVERSION=\"$(VERSION)\" \
+ /DSUFX=\"$(SUFX)\" \
+ /DPROJECT=\"$(PROJECT)\" \
+ /DPRJLIBNAME=\"$(PRJLIBNAME)\"
+
+!ifndef DEFAULT_BUILD_TARGET
+DEFAULT_BUILD_TARGET = $(PROJECT)
!endif
+
+default-target: $(DEFAULT_BUILD_TARGET)
+
+!if $(MULTIPLATFORM_INSTALL)
+default-pkgindex:
+ @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } else { >> $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PLATFORM_IDENTIFY) $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } >> $(OUT_DIR)\pkgIndex.tcl
!else
-_TKDIR = $(TKDIR:/=\)
-!if exist("$(_TKDIR)\include\tk.h")
-TKINSTALL = 1
-_TK_H = $(_TKDIR)\include\tk.h
-!elseif exist("$(_TKDIR)\generic\tk.h")
-TKINSTALL = 0
-_TK_H = $(_TKDIR)\generic\tk.h
+default-pkgindex:
+ @echo if {[package vsatisfies [package provide Tcl] 9.0-]} { > $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PRJLIBNAME9)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } else { >> $(OUT_DIR)\pkgIndex.tcl
+ @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \
+ [list load [file join $$dir $(PRJLIBNAME8)]] >> $(OUT_DIR)\pkgIndex.tcl
+ @echo } >> $(OUT_DIR)\pkgIndex.tcl
+!endif
+
+default-pkgindex-tea:
+ @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl
+@PACKAGE_VERSION@ $(DOTVERSION)
+@PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME)
+@PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME)
+@PKG_LIB_FILE@ $(PRJLIBNAME)
+@PKG_LIB_FILE8@ $(PRJLIBNAME8)
+@PKG_LIB_FILE9@ $(PRJLIBNAME9)
+<<
+
+default-install: default-install-binaries default-install-libraries
+!if $(SYMBOLS)
+default-install: default-install-pdbs
+!endif
+
+# Again to deal with historical brokenness, there is some confusion
+# in terminlogy. For extensions, the "install-binaries" was used to
+# locate target directory for *binary shared libraries* and thus
+# the appropriate macro is LIB_INSTALL_DIR since BIN_INSTALL_DIR is
+# for executables (exes). On the other hand the "install-libraries"
+# target is for *scripts* and should have been called "install-scripts".
+default-install-binaries: $(PRJLIB)
+ @echo Installing binaries to '$(LIB_INSTALL_DIR)'
+ @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
+ @$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL
+
+# Alias for default-install-scripts
+default-install-libraries: default-install-scripts
+
+default-install-scripts: $(OUT_DIR)\pkgIndex.tcl
+ @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
+ @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
+ @echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
+ @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR)
+
+default-install-stubs:
+ @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)'
+ @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
+ @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL
+
+default-install-pdbs:
+ @echo Installing PDBs to '$(LIB_INSTALL_DIR)'
+ @if not exist "$(LIB_INSTALL_DIR)" mkdir "$(LIB_INSTALL_DIR)"
+ @$(CPY) "$(OUT_DIR)\*.pdb" "$(LIB_INSTALL_DIR)\"
+
+# "emacs font-lock highlighting fix
+
+default-install-docs-html:
+ @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
+ @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
+ @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
+
+default-install-docs-n:
+ @echo Installing documentation files to '$(DOC_INSTALL_DIR)'
+ @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)"
+ @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)"
+
+default-install-demos:
+ @echo Installing demos to '$(DEMO_INSTALL_DIR)'
+ @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)"
+ @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)"
+
+default-clean:
+ @echo Cleaning $(TMP_DIR)\* ...
+ @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR)
+ @echo Cleaning $(WIN_DIR)\nmakehlp.obj, nmakehlp.exe ...
+ @if exist $(WIN_DIR)\nmakehlp.obj del $(WIN_DIR)\nmakehlp.obj
+ @if exist $(WIN_DIR)\nmakehlp.exe del $(WIN_DIR)\nmakehlp.exe
+ @if exist $(WIN_DIR)\nmakehlp.out del $(WIN_DIR)\nmakehlp.out
+ @echo Cleaning $(WIN_DIR)\nmhlp-out.txt ...
+ @if exist $(WIN_DIR)\nmhlp-out.txt del $(WIN_DIR)\nmhlp-out.txt
+ @echo Cleaning $(WIN_DIR)\_junk.pch ...
+ @if exist $(WIN_DIR)\_junk.pch del $(WIN_DIR)\_junk.pch
+ @echo Cleaning $(WIN_DIR)\vercl.x, vercl.i ...
+ @if exist $(WIN_DIR)\vercl.x del $(WIN_DIR)\vercl.x
+ @if exist $(WIN_DIR)\vercl.i del $(WIN_DIR)\vercl.i
+ @echo Cleaning $(WIN_DIR)\versions.vc, version.vc ...
+ @if exist $(WIN_DIR)\versions.vc del $(WIN_DIR)\versions.vc
+ @if exist $(WIN_DIR)\version.vc del $(WIN_DIR)\version.vc
+
+default-hose: default-clean
+ @echo Hosing $(OUT_DIR)\* ...
+ @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR)
+
+# Only for backward compatibility
+default-distclean: default-hose
+
+default-setup:
+ @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR)
+ @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR)
+
+!if "$(TESTPAT)" != ""
+TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT)
+!endif
+
+default-test: default-setup $(PROJECT)
+ @set TCLLIBPATH=$(OUT_DIR:\=/)
+ @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)"
+ cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS)
+
+default-shell: default-setup $(PROJECT)
+ @set TCLLIBPATH=$(OUT_DIR:\=/)
+ @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)"
+ $(DEBUGGER) $(TCLSH)
+
+# Generation of Windows version resource
+!ifdef RCFILE
+
+# Note: don't use $** in below rule because there may be other dependencies
+# and only the "main" rc must be passed to the resource compiler
+$(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc
+ $(RESCMD) $(RCDIR)\$(PROJECT).rc
+
!else
-MSG =^
-Failed to find tk.h. The TKDIR macro does not appear correct.
-!error $(MSG)
-!endif
-!endif
+
+# If parent makefile has not defined a resource definition file,
+# we will generate one from standard template.
+$(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc
+
+$(TMP_DIR)\$(PROJECT).rc:
+ @$(COPY) << $(TMP_DIR)\$(PROJECT).rc
+#include
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION COMMAVERSION
+ PRODUCTVERSION COMMAVERSION
+ FILEFLAGSMASK 0x3fL
+#ifdef DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Tcl extension " PROJECT
+ VALUE "OriginalFilename", PRJLIBNAME
+ VALUE "FileVersion", DOTVERSION
+ VALUE "ProductName", "Package " PROJECT " for Tcl"
+ VALUE "ProductVersion", DOTVERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+<<
+
+!endif # ifdef RCFILE
+
+!ifndef DISABLE_IMPLICIT_RULES
+DISABLE_IMPLICIT_RULES = 0
!endif
-#-------------------------------------------------------------------------
-# Extract Tk version numbers
-#-------------------------------------------------------------------------
+!if !$(DISABLE_IMPLICIT_RULES)
+# Implicit rule definitions - only for building library objects. For stubs and
+# main application, the makefile should define explicit rules.
-!if defined(PROJECT_REQUIRES_TK) || "$(PROJECT)" == "tk"
+{$(ROOT)}.c{$(TMP_DIR)}.obj::
+ $(CCPKGCMD) @<<
+$<
+<<
+
+{$(WIN_DIR)}.c{$(TMP_DIR)}.obj::
+ $(CCPKGCMD) @<<
+$<
+<<
+
+{$(GENERICDIR)}.c{$(TMP_DIR)}.obj::
+ $(CCPKGCMD) @<<
+$<
+<<
+
+{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
+ $(CCPKGCMD) @<<
+$<
+<<
+
+{$(RCDIR)}.rc{$(TMP_DIR)}.res:
+ $(RESCMD) $<
+
+{$(WIN_DIR)}.rc{$(TMP_DIR)}.res:
+ $(RESCMD) $<
+
+{$(TMP_DIR)}.rc{$(TMP_DIR)}.res:
+ $(RESCMD) $<
+
+.SUFFIXES:
+.SUFFIXES:.c .rc
-!if [echo TK_MAJOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc]
!endif
-!if [echo TK_MINOR_VERSION = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc]
+
+################################################################
+# 14. Sanity check selected options against Tcl build options
+# When building an extension, certain configuration options should
+# match the ones used when Tcl was built. Here we check and
+# warn on a mismatch.
+!if !$(DOING_TCL)
+
+!if $(TCLINSTALL) # Building against an installed Tcl
+!if exist("$(_TCLDIR)\lib\nmake\tcl.nmake")
+TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake"
!endif
-!if [echo TK_PATCH_LEVEL = \>> versions.vc] \
- && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc]
+!else # !$(TCLINSTALL) - building against Tcl source
+!if exist("$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake")
+TCLNMAKECONFIG = "$(_TCLDIR)\win\$(BUILDDIRTOP)\tcl.nmake"
!endif
+!endif # TCLINSTALL
-!include versions.vc
-
-TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION)
-TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION)
+!if $(CONFIG_CHECK)
+!ifdef TCLNMAKECONFIG
+!include $(TCLNMAKECONFIG)
-!if "$(PROJECT)" != "tk"
-!if $(TKINSTALL)
-WISH = "$(_TKDIR)\bin\wish$(TK_VERSION)$(SUFX).exe"
-TKSTUBLIB = "$(_TKDIR)\lib\tkstub$(TK_VERSION).lib"
-TKIMPLIB = "$(_TKDIR)\lib\tk$(TK_VERSION)$(SUFX).lib"
-TK_INCLUDES = -I"$(_TKDIR)\include"
-!else
-WISH = "$(_TKDIR)\win\$(BUILDDIRTOP)\wish$(TCL_VERSION)$(SUFX).exe"
-TKSTUBLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tkstub$(TCL_VERSION).lib"
-TKIMPLIB = "$(_TKDIR)\win\$(BUILDDIRTOP)\tk$(TCL_VERSION)$(SUFX).lib"
-TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
+!if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)"
+!error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)).
!endif
+!if $(TCL_VERSION) < 87 && defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC)
+!message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)).
!endif
-
+!if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG)
+!message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)).
!endif
+!endif
+
+!endif # TCLNMAKECONFIG
+
+!endif # !$(DOING_TCL)
+
#----------------------------------------------------------
# Display stats being used.
#----------------------------------------------------------
+!if !$(DOING_TCL)
+!message *** Building against Tcl at '$(_TCLDIR)'
+!endif
+!if !$(DOING_TK) && $(NEED_TK)
+!message *** Building against Tk at '$(_TKDIR)'
+!endif
!message *** Intermediate directory will be '$(TMP_DIR)'
!message *** Output directory will be '$(OUT_DIR)'
+!message *** Installation, if selected, will be in '$(_INSTALLDIR)'
!message *** Suffix for binaries will be '$(SUFX)'
-!message *** Optional defines are '$(OPTDEFINES)'
-!message *** Compiler version $(VCVER). Target machine is $(MACHINE)
-!message *** Host architecture is $(NATIVE_ARCH)
-!message *** Compiler options '$(COMPILERFLAGS) $(OPTIMIZATIONS) $(DEBUGFLAGS) $(WARNINGS)'
-!message *** Link options '$(LINKERFLAGS)'
-
-!endif
+!message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH).
+!endif # ifdef _RULES_VC
diff --git a/autoconf/tea/win/targets.vc b/autoconf/tea/win/targets.vc
new file mode 100644
index 0000000000..49ed7d4a41
--- /dev/null
+++ b/autoconf/tea/win/targets.vc
@@ -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/main/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
diff --git a/autosetup/LICENSE b/autosetup/LICENSE
new file mode 100644
index 0000000000..4fe636c9d9
--- /dev/null
+++ b/autosetup/LICENSE
@@ -0,0 +1,35 @@
+Unless explicitly stated, all files which form part of autosetup
+are released under the following license:
+
+---------------------------------------------------------------------
+autosetup - A build environment "autoconfigurator"
+
+Copyright (c) 2010-2011, WorkWare Systems
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
+SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of WorkWare Systems.
diff --git a/autosetup/README.autosetup b/autosetup/README.autosetup
new file mode 100644
index 0000000000..3952980480
--- /dev/null
+++ b/autosetup/README.autosetup
@@ -0,0 +1,11 @@
+README.autosetup created by autosetup v0.7.2
+
+This is the autosetup directory for a local install of autosetup.
+It contains autosetup, support files and loadable modules.
+
+*.tcl files in this directory are optional modules which
+can be loaded with the 'use' directive.
+
+*.auto files in this directory are auto-loaded.
+
+For more information, see https://msteveb.github.io/autosetup/
diff --git a/autosetup/README.md b/autosetup/README.md
new file mode 100644
index 0000000000..2d6cf723c0
--- /dev/null
+++ b/autosetup/README.md
@@ -0,0 +1,380 @@
+Maintaining Autosetup in the SQLite Tree
+========================================================================
+
+This document provides some tips and reminders for the SQLite
+developers regarding using and maintaining the [Autosetup][]-based
+build infrastructure. It is not an [Autosetup][] reference.
+
+**Table of Contents**:
+
+- [Autosetup API Reference](#apiref)
+- [API Tips](#apitips)
+- [Ensuring TCL Compatibility](#tclcompat)
+- [Design Conventions](#conventions)
+ - Symbolic Names of Feature Flags
+ - Do Not Update Global Shared State
+- [Updating Autosetup](#updating)
+ - [Patching Autosetup for Project-local changes](#patching)
+
+------------------------------------------------------------------------
+
+
+Autosetup API Reference
+========================================================================
+
+The Autosetup API is quite extensive and can be read either in
+the [files in the `autosetup` dir](/dir/autosetup) or using:
+
+>
+```
+$ ./configure --reference | less
+```
+
+That will include any docs from any TCL files in the `./autosetup` dir
+which contain certain (simple) markup defined by autosetup.
+
+This project's own configuration-related TCL code is spread across the
+following files:
+
+- [proj.tcl][]: project-agnostic utility code for autosetup-driven
+ projects. This file is designed to be shared between this project,
+ other projects managed under the SQLite/Hwaci umbrella
+ (e.g. Fossil), and personal projects of SQLite's developers. It is
+ essentially an amalgamation of a decade's worth of autosetup-related
+ utility code.
+- [auto.def][]: the primary driver for the `./configure` process.
+ When we talk about "the configure script," we're referring to
+ this file.
+- [sqlite-config.tcl][]: utility code which is too project-specific
+ for `proj.tcl`. We split this out of `auto.def` so that it can be
+ used by both `auto.def` and...
+- [autoconf/auto.def][]: the main driver script for the "autoconf"
+ bundle's configure script. It is essentially a slightly trimmed-down
+ version of the main `auto.def` file. The `autoconf` dir was ported
+ from the Autotools to Autosetup in the 3.49.0 dev cycle but retains
+ the "autoconf" name to minimize downstream disruption.
+
+
+
+Autosetup API Tips
+========================================================================
+
+This section briefly covers only APIs which are frequently useful in
+day-to-day maintenance and might not be immediately recognized as such
+obvious from a casual perusal of the relevant TCL files. The complete
+docs of those with `proj-` prefix can be found in [proj.tcl][] and
+those with an `sqlite-` prefix are in [sqlite-config.tcl][]. The
+others are scattered around [the TCL files in
+./autosetup](/dir/autosetup).
+
+In (mostly) alphabetical order:
+
+- **`file-isexec filename`**\
+ Should be used in place of `[file executable]`, as it will also
+ check for `${filename}.exe` on Windows platforms. However, on such
+ platforms it also assumes that _any_ existing file is executable.
+
+- **`get-env VAR ?default?`**\
+ Will fetch an "environment variable" from the first of either: (1) a
+ KEY=VALUE passed to the configure script or (2) the system's
+ environment variables. Not to be confused with `getenv`, which only
+ does the latter and is rarely, if ever, useful in this tree.
+ - **`proj-get-env VAR ?default?`**\
+ Works like `get-env` but will, if that function finds no match,
+ look for a file named `./.env-$VAR` and, if found, return its
+ trimmed contents. This can be used, e.g., to set a developer's
+ local preferences for the default `CFLAGS`.
+
+- **`define-for-opt flag defineName ?checkingMsg? ?yesVal=1? ?noVal=0?`**\
+ `[define $defineName]` to either `$yesVal` or `$noVal`, depending on
+ whether `--$flag` is truthy or not. `$checkingMsg` is a
+ human-readable description of the check being made, e.g. "enable foo?"
+ If no `checkingMsg` is provided, the operation is silent.\
+ Potential TODO: change the final two args to `-yes` and `-no`
+ flags. They're rarely needed, though: search [auto.def][] for
+ `TSTRNNR_OPTS` for an example of where they are used.
+
+- **`proj-fatal msg`**\
+ Emits `$msg` to stderr and exits with non-zero.
+
+- **`proj-if-opt-truthy flag thenScript ?elseScript?`**\
+ Evals `thenScript` if the given `--flag` is truthy, else it
+ evals the optional `elseScript`.
+
+- **`proj-indented-notice ?-error? ?-notice? msg`**\
+ Breaks its `msg` argument into lines, trims them, and emits them
+ with consistent indentation. Exactly how it emits depends on the
+ flags passed to it (or not), as covered in its docs. This will stick
+ out starkly from normal output and is intended to be used only for
+ important notices.
+
+- **`proj-opt-truthy flag`**\
+ Returns 1 if `--flag`'s value is "truthy," i.e. one of (1, on,
+ enabled, yes, true).
+
+- **`proj-opt-was-provided FLAG`**\
+ Returns 1 if `--FLAG` was explicitly provided to configure,
+ else 0. This distinction can be used to determine, e.g., whether
+ `--with-readline` was provided or whether we're searching for
+ readline by default. In the former case, failure to find it should
+ be treated as fatal, where in the latter case it's not.
+
+- **`proj-val-truthy value`**\
+ Returns 1 if `$value` is "truthy," See `proj-opt-truthy` for the definition
+ of "truthy."
+
+- **`proj-warn msg`**\
+ Emits `$msg` to stderr. Closely-related is autosetup's `user-notice`
+ (described below).
+
+- **`sqlite-add-feature-flag ?-shell? FLAG...`**\
+ Adds the given feature flag to the CFLAGS which are specific to
+ building libsqlite3. It's intended to be passed one or more
+ `-DSQLITE_ENABLE_...`, or similar, flags. If the `-shell` flag is
+ used then it also passes its arguments to
+ `sqlite-add-shell-opt`. This is a no-op if `FLAG` is not provided or
+ is empty.
+
+- **`sqlite-add-shell-opt FLAG...`**\
+ The shell-specific counterpart of `sqlite-add-feature-flag` which
+ only adds the given flag(s) to the CLI-shell-specific CFLAGS.
+
+- **`user-notice msg`**\
+ Queues `$msg` to be sent to stderr, but does not emit it until
+ either `show-notices` is called or the next time autosetup would
+ output something (it internally calls `show-notices`). This can be
+ used to generate warnings between a "checking for..." message and
+ its resulting "yes/no/whatever" message in such a way as to not
+ spoil the layout of such messages.
+
+
+
+Ensuring TCL Compatibility
+========================================================================
+
+It is important that any TCL files used by the configure process
+remain compatible with both [JimTCL][] and the canonical TCL. Though
+JimTCL has outstanding compatibility with canonical TCL, it does have
+a few corners with incompatibilities, e.g. regular expressions. If a
+script runs in JimTCL without using any JimTCL-specific features, then
+it's a certainty that it will run in canonical TCL as well. The
+opposite, however, is not _always_ the case.
+
+When [`./configure`](/file/configure) is run, it goes through a
+bootstrapping process to find a suitable TCL with which to run the
+autosetup framework. The first step involves [finding or building a
+TCL shell](/file/autosetup/autosetup-find-tclsh). That will first
+search for an available `tclsh` (under several common names,
+e.g. `tclsh8.6`) before falling back to compiling the copy of
+`jimsh0.c` included in the source tree. i.e. it will prefer to use a
+system-installed TCL for running the configure script. Once it finds
+(or builds) a TCL shell, it then runs [a sanity test to ensure that
+the shell is suitable](/file/autosetup/autosetup-test-tclsh) before
+using it to run the main autosetup app.
+
+There are two simple ways to ensure that running of the configure
+process uses JimTCL instead of the canonical `tclsh`, and either
+approach provides equally high assurances about configure script
+compatibility across TCL implementations:
+
+1. Build on a system with no `tclsh` installed in the `$PATH`. In that
+ case, the configure process will fall back to building the in-tree
+ copy of JimTCL.
+
+2. Manually build `./jimsh0` in the top of the checkout with:\
+ `cc -o jimsh0 autosetup/jimsh0.c`\
+ With that in place, the configure script will prefer to use that
+ before looking for a system-level `tclsh`. Be aware, though, that
+ `make distclean` will remove that file.
+
+**Note that `jimsh0` is distinctly different from the `jimsh`** which
+gets built for code-generation purposes. The latter requires
+non-default build flags to enable features which are
+platform-dependent, most notably to make its `[file normalize]` work.
+This means, for example, that the configure script and its utility
+APIs must not use `[file normalize]`, but autosetup provides a
+TCL-only implementation of `[file-normalize]` (note the dash) for
+portable use in the configure script.
+
+Known TCL Incompatibilities
+------------------------------------------------------------------------
+
+A summary of known incompatibilities in JimTCL
+
+- **CRNL line endings**: prior to 2025-02-05 `fconfigure -translation ...`
+ was a no-op in JimTCL, and it emits CRNL line endings by default on
+ Windows. Since then, it supports `-translation binary`, which is
+ close enough to `-translation lf` for our purposes. When working
+ with files using the `open` command, it is important to use mode
+ `"rb"` or `"wb"`, as appropriate, so that the output does not get
+ CRNL-mangled on Windows.
+
+- **`file copy`** does not support multiple source files. See
+ [](/info/61f18c96183867fe) for a workaround.
+
+- **Regular expressions**:
+
+ - Patterns treat `\nnn` octal values as back-references (which it
+ does not support). Those can be reformulated as demonstrated in
+ [](/info/aeac23359bb681c0).
+
+ - `regsub` does not support the `\y` flag. A workaround is demonstrated
+ in [](/info/c2e5dd791cce3ec4).
+
+
+Design Conventions
+========================================================================
+
+This section describes the motivations for the most glaring of the
+build's design decisions, in particular how they deviate from
+historical, or even widely-conventional, practices.
+
+Symbolic Names of Feature Flags
+------------------------------------------------------------------------
+
+Historically, the project's makefile has exclusively used
+`UPPER_UNDERSCORE` form for makefile variables. This build, however,
+primarily uses `X.y` format, where `X` is often a category label,
+e.g. `CFLAGS`, and `y` is the specific instance of that category,
+e.g. `CFLAGS.readline`.
+
+When the configure script exports flags for consumption by filtered
+files, e.g. [Makefile.in][] and the generated
+`sqlite_cfg.h`, it does so in the more conventional `X_Y` form because
+those flags get exported as as C `#define`s to `sqlite_cfg.h`, where
+dots are not permitted.
+
+The `X.y` convention is used in the makefiles primarily because the
+person who did the initial port finds that considerably easier on the
+eyes and fingers. In practice, the `X_Y` form of such exports is used
+exactly once in [Makefile.in][], where it's translated into into `X.y`
+form for consumption by [Makefile.in][] and [main.mk][]. For example:
+
+>
+```
+LDFLAGS.shobj = @SHOBJ_LDFLAGS@
+LDFLAGS.zlib = @LDFLAGS_ZLIB@
+LDFLAGS.math = @LDFLAGS_MATH@
+```
+
+(That first one is defined by autosetup, and thus applies "LDFLAGS" as
+the suffix rather than the prefix. Which is more legible is a matter
+of taste, for which there is no accounting.)
+
+
+Do Not Update Global Shared State
+------------------------------------------------------------------------
+
+In both the legacy Autotools-driven build and in common Autosetup
+usage, feature tests performed by the configure script may amend
+global flags such as `LIBS`, `LDFLAGS`, and `CFLAGS`[^as-cflags]. That's
+appropriate for a makefile which builds a single deliverable, but less
+so for makefiles which produce multiple deliverables. Drawbacks of
+that approach include:
+
+- It's unlikely that every single deliverable will require the same
+ core set of those flags.
+- It can be difficult to determine the origin of any given change to
+ that global state because those changes are hidden behind voodoo performed
+ outside the immediate visibility of the configure script's
+ maintainer.
+- It can force the maintainers of the configure script to place tests
+ in a specific order so that the resulting flags get applied at
+ the correct time and/or in the correct order.\
+ (A real-life example: before the approach described below was taken
+ to collecting build-time flags, the test for `-rpath` had to come
+ _after_ the test for zlib because the results of the `-rpath` test
+ implicitly modified global state which broke the zlib feature
+ test. Because the feature tests no longer (intentionally) modify
+ shared global state, that is not an issue.)
+
+In this build, cases where feature tests modify global state in such a
+way that it may impact later feature tests are either (A) very
+intentionally defined to do so (e.g. the `--with-wasi-sdk` flag has
+invasive side-effects) or (B) are oversights (i.e. bugs).
+
+This tree's [configure script][auto.def], [utility APIs][proj.tcl],
+[Makefile.in][], and [main.mk][] therefore strive to separate the
+results of any given feature test into its own well-defined
+variables. For example:
+
+- The linker flags for zlib are exported from the configure script as
+ `LDFLAGS_ZLIB`, which [Makefile.in][] and [main.mk][] then expose as
+ `LDFLAGS.zlib`.
+- `CFLAGS_READLINE` (a.k.a. `CFLAGS.readline`) contains the `CFLAGS`
+ needed for including `libreadline`, `libedit`, or `linenoise`, and
+ `LDFLAGS_READLINE` (a.k.a. `LDFLAGS.readline`) is its link-time
+ counterpart.
+
+It is then up to the Makefile to apply and order the flags however is
+appropriate.
+
+At the end of the configure script, the global `CFLAGS` _ideally_
+holds only flags which are either relevant to all targets or, failing
+that, will have no unintended side-effects on any targets. That said:
+clients frequently pass custom `CFLAGS` to `./configure` or `make` to
+set library-level feature toggles, e.g. `-DSQLITE_OMIT_FOO`, in which
+case there is no practical way to avoid "polluting" the builds of
+arbitrary makefile targets with those. _C'est la vie._
+
+
+[^as-cflags]: But see this article for a detailed discussion of how
+ autosetup currently deals specifically with CFLAGS:
+
+
+
+
+Updating Autosetup
+========================================================================
+
+Updating autosetup is, more often than not, painless. It requires having
+a checked-out copy of [the autosetup git repository][autosetup-git]:
+
+>
+```
+$ git clone https://github.com/msteveb/autosetup
+$ cd autosetup
+# Or, if it's already checked out:
+$ git pull
+```
+
+Then, from the top-most directory of an SQLite checkout:
+
+>
+```
+$ /path/to/autosetup-checkout/autosetup --install .
+$ fossil status # show the modified files
+```
+
+Unless the upgrade made any incompatible changes (which is exceedingly
+rare), that's all there is to it. After that's done, **apply a patch
+for the change described in the following section**, test the
+configure process, and check it in.
+
+
+Patching Autosetup for Project-local Changes
+------------------------------------------------------------------------
+
+Autosetup reserves the flag name **`--debug`** for its own purposes,
+and its own special handling of `--enable-...` flags makes `--debug`
+an alias for `--enable-debug`. As we have a long history of using
+`--enable-debug` for this project's own purposes, we patch autosetup
+to use the name `--autosetup-debug` in place of `--debug`. That
+requires (as of this writing) four small edits in
+[](/file/autosetup/autosetup), as demonstrated in [check-in
+3296c8d3](/info/3296c8d3).
+
+If autosetup is upgraded and this patch is _not_ applied the invoking
+`./configure` will fail loudly because of the declaration of the
+`debug` flag in `auto.def` - duplicated flags are not permitted.
+
+
+[Autosetup]: https://msteveb.github.io/autosetup/
+[auto.def]: /file/auto.def
+[autoconf/auto.def]: /file/autoconf/auto.def
+[autosetup-git]: https://github.com/msteveb/autosetup
+[proj.tcl]: /file/autosetup/proj.tcl
+[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
+[Makefile.in]: /file/Makefile.in
+[main.mk]: /file/main.mk
+[JimTCL]: https://jim.tcl.tk
diff --git a/autosetup/autosetup b/autosetup/autosetup
new file mode 100755
index 0000000000..239987554f
--- /dev/null
+++ b/autosetup/autosetup
@@ -0,0 +1,2540 @@
+#!/bin/sh
+# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+# vim:se syntax=tcl:
+# \
+dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
+
+# Note that the version has a trailing + on unreleased versions
+set autosetup(version) 0.7.2
+
+# Can be set to 1 to debug early-init problems
+set autosetup(debug) [expr {"--autosetup-debug" in $argv}]
+
+##################################################################
+#
+# Main flow of control, option handling
+#
+proc main {argv} {
+ global autosetup define
+
+ # There are 3 potential directories involved:
+ # 1. The directory containing autosetup (this script)
+ # 2. The directory containing auto.def
+ # 3. The current directory
+
+ # From this we need to determine:
+ # a. The path to this script (and related support files)
+ # b. The path to auto.def
+ # c. The build directory, where output files are created
+
+ # This is also complicated by the fact that autosetup may
+ # have been run via the configure wrapper ([getenv WRAPPER] is set)
+
+ # Here are the rules.
+ # a. This script is $::argv0
+ # => dir, prog, exe, libdir
+ # b. auto.def is in the directory containing the configure wrapper,
+ # otherwise it is in the current directory.
+ # => srcdir, autodef
+ # c. The build directory is the current directory
+ # => builddir, [pwd]
+
+ # 'misc' is needed before we can do anything, so set a temporary libdir
+ # in case this is the development version
+ set autosetup(libdir) [file dirname $::argv0]/lib
+ use misc
+
+ # (a)
+ set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
+ set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
+ set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
+ if {$autosetup(installed)} {
+ set autosetup(libdir) $autosetup(dir)
+ } else {
+ set autosetup(libdir) [file join $autosetup(dir) lib]
+ }
+ autosetup_add_dep $autosetup(prog)
+
+ # (b)
+ if {[getenv WRAPPER ""] eq ""} {
+ # Invoked directly
+ set autosetup(srcdir) [pwd]
+ } else {
+ # Invoked via the configure wrapper
+ set autosetup(srcdir) [file-normalize [file dirname $autosetup(exe)]]
+ }
+ set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]
+
+ # (c)
+ set autosetup(builddir) [pwd]
+
+ set autosetup(argv) $argv
+ set autosetup(cmdline) {}
+ # options is a list of known options
+ set autosetup(options) {}
+ # optset is a dictionary of option values set by the user based on getopt
+ set autosetup(optset) {}
+ # optdefault is a dictionary of default values
+ set autosetup(optdefault) {}
+ # options-defaults is a dictionary of overrides for default values for options
+ set autosetup(options-defaults) {}
+ set autosetup(optionhelp) {}
+ set autosetup(showhelp) 0
+
+ use util
+
+ # Parse options
+ use getopt
+
+ # At the is point we don't know what is a valid option
+ # We simply parse anything that looks like an option
+ set autosetup(getopt) [getopt argv]
+
+ #"=Core Options:"
+ options-add {
+ help:=all => "display help and options. Optional: module name, such as --help=system"
+ licence license => "display the autosetup license"
+ version => "display the version of autosetup"
+ ref:=text manual:=text
+ reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
+ autosetup-debug => "display debugging output as autosetup runs"
+ install:=. => "install autosetup to the current or given directory"
+ }
+ if {$autosetup(installed)} {
+ # hidden options so we can produce a nice error
+ options-add {
+ sysinstall:path
+ }
+ } else {
+ options-add {
+ sysinstall:path => "install standalone autosetup to the given directory (e.g.: /usr/local)"
+ }
+ }
+ options-add {
+ force init:=help => "create initial auto.def, etc. Use --init=help for known types"
+ # Undocumented options
+ option-checking=1
+ nopager
+ quiet
+ timing
+ conf:
+ }
+
+ if {[opt-bool version]} {
+ puts $autosetup(version)
+ exit 0
+ }
+
+ # autosetup --conf=alternate-auto.def
+ if {[opt-str conf o]} {
+ set autosetup(autodef) $o
+ }
+
+ # Debugging output (set this early)
+ incr autosetup(debug) [opt-bool autosetup-debug]
+ incr autosetup(force) [opt-bool force]
+ incr autosetup(msg-quiet) [opt-bool quiet]
+ incr autosetup(msg-timing) [opt-bool timing]
+
+ # If the local module exists, source it now to allow for
+ # project-local customisations
+ if {[file exists $autosetup(libdir)/local.tcl]} {
+ use local
+ }
+
+ # Now any auto-load modules
+ autosetup_load_auto_modules
+
+ if {[opt-str help o]} {
+ incr autosetup(showhelp)
+ use help
+ autosetup_help $o
+ }
+
+ if {[opt-bool licence license]} {
+ use help
+ autosetup_show_license
+ exit 0
+ }
+
+ if {[opt-str {manual ref reference} o]} {
+ use help
+ autosetup_reference $o
+ }
+
+ # Allow combining --install and --init
+ set earlyexit 0
+ if {[opt-str install o]} {
+ use install
+ autosetup_install $o
+ incr earlyexit
+ }
+
+ if {[opt-str init o]} {
+ use init
+ autosetup_init $o
+ incr earlyexit
+ }
+
+ if {$earlyexit} {
+ exit 0
+ }
+ if {[opt-str sysinstall o]} {
+ use install
+ autosetup_install $o 1
+ exit 0
+ }
+
+ if {![file exists $autosetup(autodef)]} {
+ # Check for invalid option first
+ options {}
+ user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
+ }
+
+ # Parse extra arguments into autosetup(cmdline)
+ foreach arg $argv {
+ if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
+ dict set autosetup(cmdline) $n $v
+ define $n $v
+ } else {
+ user-error "Unexpected parameter: $arg"
+ }
+ }
+
+ autosetup_add_dep $autosetup(autodef)
+
+ # Add $argv to CONFIGURE_OPTS
+ define-append-argv CONFIGURE_OPTS {*}$autosetup(argv)
+ # Set up AUTOREMAKE to reconfigure with the same args
+ define-append-argv AUTOREMAKE {*}$autosetup(exe) {*}$autosetup(argv)
+
+ # Log how we were invoked
+ configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
+ configlog "Tclsh: [info nameofexecutable]"
+
+ # Load auto.def as module "auto.def"
+ autosetup_load_module auto.def source $autosetup(autodef)
+
+ # Could warn here if options {} was not specified
+
+ show-notices
+
+ if {$autosetup(debug)} {
+ msg-result "Writing all defines to config.log"
+ configlog "================ defines ======================"
+ foreach n [lsort [array names define]] {
+ configlog "define $n $define($n)"
+ }
+ }
+
+ exit 0
+}
+
+# @section Option Handling
+
+# @opt-bool ?-nodefault? option ...
+#
+# Check each of the named, boolean options and if any have been explicitly enabled
+# or disabled by the user, return 1 or 0 accordingly.
+#
+# If the option was specified more than once, the last value wins.
+# e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
+#
+# If no value was specified by the user, returns the default value for the
+# first option. If '-nodefault' is given, this behaviour changes and
+# -1 is returned instead.
+#
+proc opt-bool {args} {
+ set nodefault 0
+ if {[lindex $args 0] eq "-nodefault"} {
+ set nodefault 1
+ set args [lrange $args 1 end]
+ }
+ option-check-names {*}$args
+
+ foreach opt $args {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ return [dict get $::autosetup(optset) $opt]
+ }
+ }
+
+ if {$nodefault} {
+ return -1
+ }
+ # Default value is the default for the first option
+ return [dict get $::autosetup(optdefault) [lindex $args 0]]
+}
+
+# @opt-val optionlist ?default=""?
+#
+# Returns a list containing all the values given for the non-boolean options in '$optionlist'.
+# There will be one entry in the list for each option given by the user, including if the
+# same option was used multiple times.
+#
+# If no options were set, '$default' is returned (exactly, not as a list).
+#
+# Note: For most use cases, 'opt-str' should be preferred.
+#
+proc opt-val {names {default ""}} {
+ option-check-names {*}$names
+
+ foreach opt $names {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ lappend result {*}[dict get $::autosetup(optset) $opt]
+ }
+ }
+ if {[info exists result]} {
+ return $result
+ }
+ return $default
+}
+
+# @opt-str optionlist varname ?default?
+#
+# Sets '$varname' in the callers scope to the value for one of the given options.
+#
+# For the list of options given in '$optionlist', if any value is set for any option,
+# the option value is taken to be the *last* value of the last option (in the order given).
+#
+# If no option was given, and a default was specified with 'options-defaults',
+# that value is used.
+#
+# If no 'options-defaults' value was given and '$default' was given, it is used.
+#
+# If none of the above provided a value, no value is set.
+#
+# The return value depends on whether '$default' was specified.
+# If it was, the option value is returned.
+# If it was not, 1 is returns if a value was set, or 0 if not.
+#
+# Typical usage is as follows:
+#
+## if {[opt-str {myopt altname} o]} {
+## do something with $o
+## }
+#
+# Or:
+## define myname [opt-str {myopt altname} o "/usr/local"]
+#
+proc opt-str {names varname args} {
+ global autosetup
+
+ option-check-names {*}$names
+ upvar $varname value
+
+ if {[llength $args]} {
+ # A default was given, so always return the string value of the option
+ set default [lindex $args 0]
+ set retopt 1
+ } else {
+ # No default, so return 0 or 1 to indicate if a value was found
+ set retopt 0
+ }
+
+ foreach opt $names {
+ if {[dict exists $::autosetup(optset) $opt]} {
+ set result [lindex [dict get $::autosetup(optset) $opt] end]
+ }
+ }
+
+ if {![info exists result]} {
+ # No user-specified value. Has options-defaults been set?
+ foreach opt $names {
+ if {[dict exists $::autosetup(optdefault) $opt]} {
+ set result [dict get $autosetup(optdefault) $opt]
+ }
+ }
+ }
+
+ if {[info exists result]} {
+ set value $result
+ if {$retopt} {
+ return $value
+ }
+ return 1
+ }
+
+ if {$retopt} {
+ set value $default
+ return $value
+ }
+
+ return 0
+}
+
+proc option-check-names {args} {
+ foreach o $args {
+ if {$o ni $::autosetup(options)} {
+ autosetup-error "Request for undeclared option --$o"
+ }
+ }
+}
+
+# Parse the option definition in $opts and update
+# ::autosetup(setoptions) and ::autosetup(optionhelp) appropriately
+#
+proc options-add {opts} {
+ global autosetup
+
+ # First weed out comment lines
+ set realopts {}
+ foreach line [split $opts \n] {
+ if {![string match "#*" [string trimleft $line]]} {
+ append realopts $line \n
+ }
+ }
+ set opts $realopts
+
+ for {set i 0} {$i < [llength $opts]} {incr i} {
+ set opt [lindex $opts $i]
+ if {[string match =* $opt]} {
+ # This is a special heading
+ lappend autosetup(optionhelp) [list $opt $autosetup(module)]
+ continue
+ }
+ unset -nocomplain defaultvalue equal value
+
+ #puts "i=$i, opt=$opt"
+ regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
+ if {$name in $autosetup(options)} {
+ autosetup-error "Option $name already specified"
+ }
+
+ #puts "$opt => $name $colon $equal $value"
+
+ # Find the corresponding value in the user options
+ # and set the default if necessary
+ if {[string match "-*" $opt]} {
+ # This is a documentation-only option, like "-C "
+ set opthelp $opt
+ } elseif {$colon eq ""} {
+ # Boolean option
+ lappend autosetup(options) $name
+
+ # Check for override
+ if {[dict exists $autosetup(options-defaults) $name]} {
+ # A default was specified with options-defaults, so use it
+ set value [dict get $autosetup(options-defaults) $name]
+ }
+
+ if {$value eq "1"} {
+ set opthelp "--disable-$name"
+ } else {
+ set opthelp "--$name"
+ }
+
+ # Set the default
+ if {$value eq ""} {
+ set value 0
+ }
+ set defaultvalue $value
+ dict set autosetup(optdefault) $name $defaultvalue
+
+ if {[dict exists $autosetup(getopt) $name]} {
+ # The option was specified by the user. Look at the last value.
+ lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
+ if {$type eq "str"} {
+ # Can we convert the value to a boolean?
+ if {$setvalue in {1 enabled yes}} {
+ set setvalue 1
+ } elseif {$setvalue in {0 disabled no}} {
+ set setvalue 0
+ } else {
+ user-error "Boolean option $name given as --$name=$setvalue"
+ }
+ }
+ dict set autosetup(optset) $name $setvalue
+ #puts "Found boolean option --$name=$setvalue"
+ }
+ } else {
+ # String option.
+ lappend autosetup(options) $name
+
+ if {$equal ne "="} {
+ # Was the option given as "name:value=default"?
+ # If so, set $value to the display name and $defaultvalue to the default
+ # (This is the preferred way to set a default value for a string option)
+ if {[regexp {^([^=]+)=(.*)$} $value -> value defaultvalue]} {
+ dict set autosetup(optdefault) $name $defaultvalue
+ }
+ }
+
+ # Maybe override the default value
+ if {[dict exists $autosetup(options-defaults) $name]} {
+ # A default was specified with options-defaults, so use it
+ set defaultvalue [dict get $autosetup(options-defaults) $name]
+ dict set autosetup(optdefault) $name $defaultvalue
+ } elseif {![info exists defaultvalue]} {
+ # No default value was given by value=default or options-defaults
+ # so use the value as the default when the plain option with no
+ # value is given (.e.g. just --opt instead of --opt=value)
+ set defaultvalue $value
+ }
+
+ if {$equal eq "="} {
+ # String option with optional value
+ set opthelp "--$name?=$value?"
+ } else {
+ # String option with required value
+ set opthelp "--$name=$value"
+ }
+
+ # Get the values specified by the user
+ if {[dict exists $autosetup(getopt) $name]} {
+ set listvalue {}
+
+ foreach pair [dict get $autosetup(getopt) $name] {
+ lassign $pair type setvalue
+ if {$type eq "bool" && $setvalue} {
+ if {$equal ne "="} {
+ user-error "Option --$name requires a value"
+ }
+ # If given as a boolean, use the default value
+ set setvalue $defaultvalue
+ }
+ lappend listvalue $setvalue
+ }
+
+ #puts "Found string option --$name=$listvalue"
+ dict set autosetup(optset) $name $listvalue
+ }
+ }
+
+ # Now create the help for this option if appropriate
+ if {[lindex $opts $i+1] eq "=>"} {
+ set desc [lindex $opts $i+2]
+ if {[info exists defaultvalue]} {
+ set desc [string map [list @default@ $defaultvalue] $desc]
+ }
+ # A multi-line description
+ lappend autosetup(optionhelp) [list $opthelp $autosetup(module) $desc]
+ incr i 2
+ }
+ }
+}
+
+# @module-options optionlist
+#
+# Deprecated. Simply use 'options' from within a module.
+proc module-options {opts} {
+ options $opts
+}
+
+proc max {a b} {
+ expr {$a > $b ? $a : $b}
+}
+
+proc options-wrap-desc {text length firstprefix nextprefix initial} {
+ set len $initial
+ set space $firstprefix
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word == ""} {
+ continue
+ }
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {$len} {
+ puts ""
+ }
+}
+
+# Display options (from $autosetup(optionhelp)) for modules that match
+# glob pattern $what
+proc options-show {what} {
+ set local 0
+ # Determine the max option width
+ set max 0
+ foreach help $::autosetup(optionhelp) {
+ lassign $help opt module desc
+ if {![string match $what $module]} {
+ continue
+ }
+ if {[string match =* $opt] || [string match \n* $desc]} {
+ continue
+ }
+ set max [max $max [string length $opt]]
+ }
+ set indent [string repeat " " [expr {$max+4}]]
+ set cols [getenv COLUMNS 80]
+ catch {
+ lassign [exec stty size] _ sttycols
+ if {[string is integer -strict $sttycols]} {
+ set cols $sttycols
+ }
+ }
+ incr cols -1
+ # Now output
+ foreach help $::autosetup(optionhelp) {
+ lassign $help opt module desc
+ if {![string match $what $module]} {
+ continue
+ }
+ if {$local == 0 && $module eq "auto.def"} {
+ puts "Local Options:"
+ incr local
+ }
+ if {[string match =* $opt]} {
+ # Output a special heading line"
+ puts [string range $opt 1 end]
+ continue
+ }
+ puts -nonewline " [format %-${max}s $opt]"
+ if {[string match \n* $desc]} {
+ # Output a pre-formatted help description as-is
+ puts $desc
+ } else {
+ options-wrap-desc [string trim $desc] $cols " " $indent [expr {$max+2}]
+ }
+ }
+}
+
+# @options optionspec
+#
+# Specifies configuration-time options which may be selected by the user
+# and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
+# of options specifications separated by newlines, as follows:
+#
+# A boolean option is of the form:
+#
+## name[=0|1] => "Description of this boolean option"
+#
+# The default is 'name=0', meaning that the option is disabled by default.
+# If 'name=1' is used to make the option enabled by default, the description should reflect
+# that with text like "Disable support for ...".
+#
+# An argument option (one which takes a parameter) is of one of the following forms:
+#
+## name:value => "Description of this option"
+## name:value=default => "Description of this option with a default value"
+## name:=value => "Description of this option with an optional value"
+#
+# If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
+# If the 'name:value=default' form is used, the option has the given default value even if not
+# specified by the user.
+# If the 'name:=value' form is used, the value is optional and the given value is used
+# if it is not provided.
+#
+# The description may contain '@default@', in which case it will be replaced with the default
+# value for the option (taking into account defaults specified with 'options-defaults'.
+#
+# Undocumented options are also supported by omitting the '=> description'.
+# These options are not displayed with '--help' and can be useful for internal options or as aliases.
+#
+# For example, '--disable-lfs' is an alias for '--disable=largefile':
+#
+## lfs=1 largefile=1 => "Disable large file support"
+#
+proc options {optlist} {
+ global autosetup
+
+ options-add $optlist
+
+ if {$autosetup(showhelp)} {
+ # If --help, stop now to show help
+ return -code break
+ }
+
+ if {$autosetup(module) eq "auto.def"} {
+ # Check for invalid options
+ if {[opt-bool option-checking]} {
+ foreach o [dict keys $::autosetup(getopt)] {
+ if {$o ni $::autosetup(options)} {
+ user-error "Unknown option --$o"
+ }
+ }
+ }
+ }
+}
+
+# @options-defaults dictionary
+#
+# Specifies a dictionary of options and a new default value for each of those options.
+# Use before any 'use' statements in 'auto.def' to change the defaults for
+# subsequently included modules.
+proc options-defaults {dict} {
+ foreach {n v} $dict {
+ dict set ::autosetup(options-defaults) $n $v
+ }
+}
+
+proc config_guess {} {
+ if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} {
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} {
+ user-error $alias
+ }
+ return $alias
+ } else {
+ configlog "No autosetup-config.guess, so using uname"
+ string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
+ }
+}
+
+proc config_sub {alias} {
+ if {[file-isexec $::autosetup(dir)/autosetup-config.sub]} {
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.sub $alias} alias]} {
+ user-error $alias
+ }
+ }
+ return $alias
+}
+
+# @section Variable Definitions (defines)
+
+# @define name ?value=1?
+#
+# Defines the named variable to the given value.
+# These (name, value) pairs represent the results of the configuration check
+# and are available to be subsequently checked, modified and substituted.
+#
+proc define {name {value 1}} {
+ set ::define($name) $value
+ #dputs "$name <= $value"
+}
+
+# @define-push {name ...} script
+#
+# Save the values of the given defines, evaluation the script, then restore.
+# For example, to avoid updating AS_FLAGS and AS_CXXFLAGS:
+## define-push {AS_CFLAGS AS_CXXFLAGS} {
+## cc-check-flags -Wno-error
+## }
+proc define-push {names script} {
+ array set unset {}
+ foreach name $names {
+ if {[is-defined $name]} {
+ set save($name) [get-define $name]
+ } else {
+ set unset($name) 1
+ }
+ }
+ uplevel 1 $script
+ array set ::define [array get save]
+ foreach name [array names unset] {
+ unset -nocomplain ::define($name)
+ }
+}
+
+# @undefine name
+#
+# Undefine the named variable.
+#
+proc undefine {name} {
+ unset -nocomplain ::define($name)
+ #dputs "$name <= "
+}
+
+# @define-append name value ...
+#
+# Appends the given value(s) to the given "defined" variable.
+# If the variable is not defined or empty, it is set to '$value'.
+# Otherwise the value is appended, separated by a space.
+# Any extra values are similarly appended.
+#
+# Note that define-append is not designed to add values containing spaces.
+# If values may contain spaces, consider define-append-argv instead.
+#
+proc define-append {name args} {
+ if {[get-define $name ""] ne ""} {
+ foreach arg $args {
+ if {$arg eq ""} {
+ continue
+ }
+ append ::define($name) " " $arg
+ }
+ } else {
+ set ::define($name) [join $args]
+ }
+ #dputs "$name += [join $args] => $::define($name)"
+}
+
+# @define-append-argv name value ...
+#
+# Similar to define-append except designed to construct shell command
+# lines, including correct handling of parameters with spaces.
+#
+# Each non-empty value is quoted if necessary and then appended to the given variable
+# if it does not already exist.
+#
+proc define-append-argv {name args} {
+ set seen {}
+ set new {}
+ foreach val [list {*}[get-define $name ""] {*}$args] {
+ if {$val ne {} && ![dict exists $seen $val]} {
+ lappend new [quote-if-needed $val]
+ dict set seen $val 1
+ }
+ }
+ set ::define($name) [join $new " "]
+ #dputs "$name += [join $args] => $::define($name)"
+}
+
+# @get-define name ?default=0?
+#
+# Returns the current value of the "defined" variable, or '$default'
+# if not set.
+#
+proc get-define {name {default 0}} {
+ if {[info exists ::define($name)]} {
+ #dputs "$name => $::define($name)"
+ return $::define($name)
+ }
+ #dputs "$name => $default"
+ return $default
+}
+
+# @is-defined name
+#
+# Returns 1 if the given variable is defined.
+#
+proc is-defined {name} {
+ info exists ::define($name)
+}
+
+# @is-define-set name
+#
+# Returns 1 if the given variable is defined and is set
+# to a value other than "" or 0
+#
+proc is-define-set {name} {
+ if {[get-define $name] in {0 ""}} {
+ return 0
+ }
+ return 1
+}
+
+# @all-defines
+#
+# Returns a dictionary (name, value list) of all defined variables.
+#
+# This is suitable for use with 'dict', 'array set' or 'foreach'
+# and allows for arbitrary processing of the defined variables.
+#
+proc all-defines {} {
+ array get ::define
+}
+
+# @section Environment/Helpers
+
+# @get-env name default
+#
+# If '$name' was specified on the command line, return it.
+# Otherwise if '$name' was set in the environment, return it.
+# Otherwise return '$default'.
+#
+proc get-env {name default} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return [dict get $::autosetup(cmdline) $name]
+ }
+ getenv $name $default
+}
+
+# @env-is-set name
+#
+# Returns 1 if '$name' was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
+#
+proc env-is-set {name} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return 1
+ }
+ if {[getenv $name ""] ne ""} {
+ return 1
+ }
+ return 0
+}
+
+# @readfile filename ?default=""?
+#
+# Return the contents of the file, without the trailing newline.
+# If the file doesn't exist or can't be read, returns '$default'.
+#
+proc readfile {filename {default_value ""}} {
+ set result $default_value
+ catch {
+ set f [open $filename]
+ set result [read -nonewline $f]
+ close $f
+ }
+ return $result
+}
+
+# @writefile filename value
+#
+# Creates the given file containing '$value'.
+# Does not add an extra newline.
+#
+proc writefile {filename value} {
+ set f [open $filename w]
+ puts -nonewline $f $value
+ close $f
+}
+
+proc quote-if-needed {str} {
+ if {[string match {*[\" ]*} $str]} {
+ return \"[string map [list \" \\" \\ \\\\] $str]\"
+ }
+ return $str
+}
+
+proc quote-argv {argv} {
+ set args {}
+ foreach arg $argv {
+ lappend args [quote-if-needed $arg]
+ }
+ join $args
+}
+
+# @list-non-empty list
+#
+# Returns a copy of the given list with empty elements removed
+proc list-non-empty {list} {
+ set result {}
+ foreach p $list {
+ if {$p ne ""} {
+ lappend result $p
+ }
+ }
+ return $result
+}
+
+# @section Paths, Searching
+
+# @find-executable-path name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
+# in which case the parameters are ignored.
+# Returns the full path to the executable if found, or "" if not found.
+#
+proc find-executable-path {name} {
+ # Ignore any parameters
+ set name [lindex $name 0]
+ # The empty string is never a valid executable
+ if {$name ne ""} {
+ foreach p [split-path] {
+ dputs "Looking for $name in $p"
+ set exec [file join $p $name]
+ if {[file-isexec $exec]} {
+ dputs "Found $name -> $exec"
+ return $exec
+ }
+ }
+ }
+ return {}
+}
+
+# @find-executable name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
+# in which case the parameters are ignored.
+# Returns 1 if found, or 0 if not.
+#
+proc find-executable {name} {
+ if {[find-executable-path $name] eq {}} {
+ return 0
+ }
+ return 1
+}
+
+# @find-an-executable ?-required? name ...
+#
+# Given a list of possible executable names,
+# searches for one of these on the path.
+#
+# Returns the name found, or "" if none found.
+# If the first parameter is '-required', an error is generated
+# if no executable is found.
+#
+proc find-an-executable {args} {
+ set required 0
+ if {[lindex $args 0] eq "-required"} {
+ set args [lrange $args 1 end]
+ incr required
+ }
+ foreach name $args {
+ if {[find-executable $name]} {
+ return $name
+ }
+ }
+ if {$required} {
+ if {[llength $args] == 1} {
+ user-error "failed to find: [join $args]"
+ } else {
+ user-error "failed to find one of: [join $args]"
+ }
+ }
+ return ""
+}
+
+# @section Logging, Messages and Errors
+
+# @configlog msg
+#
+# Writes the given message to the configuration log, 'config.log'.
+#
+proc configlog {msg} {
+ if {![info exists ::autosetup(logfh)]} {
+ set ::autosetup(logfh) [open config.log w]
+ }
+ puts $::autosetup(logfh) $msg
+}
+
+# @msg-checking msg
+#
+# Writes the message with no newline to stdout.
+#
+proc msg-checking {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts -nonewline $msg
+ set ::autosetup(msg-checking) 1
+ }
+}
+
+# @msg-result msg
+#
+# Writes the message to stdout.
+#
+proc msg-result {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts $msg
+ set ::autosetup(msg-checking) 0
+ show-notices
+ }
+}
+
+# @msg-quiet command ...
+#
+# 'msg-quiet' evaluates it's arguments as a command with output
+# from 'msg-checking' and 'msg-result' suppressed.
+#
+# This is useful if a check needs to run a subcheck which isn't
+# of interest to the user.
+proc msg-quiet {args} {
+ incr ::autosetup(msg-quiet)
+ set rc [uplevel 1 $args]
+ incr ::autosetup(msg-quiet) -1
+ return $rc
+}
+
+# Will be overridden by 'use misc'
+proc error-stacktrace {msg} {
+ return $msg
+}
+
+proc error-location {msg} {
+ return $msg
+}
+
+##################################################################
+#
+# Debugging output
+#
+proc dputs {msg} {
+ if {$::autosetup(debug)} {
+ puts $msg
+ }
+}
+
+##################################################################
+#
+# User and system warnings and errors
+#
+# Usage errors such as wrong command line options
+
+# @user-error msg
+#
+# Indicate incorrect usage to the user, including if required components
+# or features are not found.
+# 'autosetup' exits with a non-zero return code.
+#
+proc user-error {msg} {
+ show-notices
+ puts stderr "Error: $msg"
+ puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
+ exit 1
+}
+
+# @user-notice msg
+#
+# Output the given message to stderr.
+#
+proc user-notice {msg} {
+ lappend ::autosetup(notices) $msg
+}
+
+# Incorrect usage in the auto.def file. Identify the location.
+proc autosetup-error {msg} {
+ autosetup-full-error [error-location $msg]
+}
+
+# Like autosetup-error, except $msg is the full error message.
+proc autosetup-full-error {msg} {
+ show-notices
+ puts stderr $msg
+ exit 1
+}
+
+proc show-notices {} {
+ if {$::autosetup(msg-checking)} {
+ puts ""
+ set ::autosetup(msg-checking) 0
+ }
+ flush stdout
+ if {[info exists ::autosetup(notices)]} {
+ puts stderr [join $::autosetup(notices) \n]
+ unset ::autosetup(notices)
+ }
+}
+
+proc maybe-show-timestamp {} {
+ if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
+ puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
+ }
+}
+
+# @autosetup-require-version required
+#
+# Checks the current version of 'autosetup' against '$required'.
+# A fatal error is generated if the current version is less than that required.
+#
+proc autosetup-require-version {required} {
+ if {[compare-versions $::autosetup(version) $required] < 0} {
+ user-error "autosetup version $required is required, but this is $::autosetup(version)"
+ }
+}
+
+proc autosetup_version {} {
+ return "autosetup v$::autosetup(version)"
+}
+
+##################################################################
+#
+# Directory/path handling
+#
+
+proc realdir {dir} {
+ set oldpwd [pwd]
+ cd $dir
+ set pwd [pwd]
+ cd $oldpwd
+ return $pwd
+}
+
+# Follow symlinks until we get to something which is not a symlink
+proc realpath {path} {
+ while {1} {
+ if {[catch {
+ set path [file readlink $path]
+ }]} {
+ # Not a link
+ break
+ }
+ }
+ return $path
+}
+
+# Convert absolute path, $path into a path relative
+# to the given directory (or the current dir, if not given).
+#
+proc relative-path {path {pwd {}}} {
+ set diff 0
+ set same 0
+ set newf {}
+ set prefix {}
+ set path [file-normalize $path]
+ if {$pwd eq ""} {
+ set pwd [pwd]
+ } else {
+ set pwd [file-normalize $pwd]
+ }
+
+ if {$path eq $pwd} {
+ return .
+ }
+
+ # Try to make the filename relative to the current dir
+ foreach p [split $pwd /] f [split $path /] {
+ if {$p ne $f} {
+ incr diff
+ } elseif {!$diff} {
+ incr same
+ }
+ if {$diff} {
+ if {$p ne ""} {
+ # Add .. for sibling or parent dir
+ lappend prefix ..
+ }
+ if {$f ne ""} {
+ lappend newf $f
+ }
+ }
+ }
+ if {$same == 1 || [llength $prefix] > 3} {
+ return $path
+ }
+
+ file join [join $prefix /] [join $newf /]
+}
+
+# Add filename as a dependency to rerun autosetup
+# The name will be normalised (converted to a full path)
+#
+proc autosetup_add_dep {filename} {
+ lappend ::autosetup(deps) [file-normalize $filename]
+}
+
+# @section Modules Support
+
+##################################################################
+#
+# Library module support
+#
+
+# @use module ...
+#
+# Load the given library modules.
+# e.g. 'use cc cc-shared'
+#
+# Note that module 'X' is implemented in either 'autosetup/X.tcl'
+# or 'autosetup/X/init.tcl'
+#
+# The latter form is useful for a complex module which requires additional
+# support file. In this form, '$::usedir' is set to the module directory
+# when it is loaded.
+#
+proc use {args} {
+ global autosetup libmodule modsource
+
+ set dirs [list $autosetup(libdir)]
+ if {[info exists autosetup(srcdir)]} {
+ lappend dirs $autosetup(srcdir)/autosetup
+ }
+ foreach m $args {
+ if {[info exists libmodule($m)]} {
+ continue
+ }
+ set libmodule($m) 1
+
+ if {[info exists modsource(${m}.tcl)]} {
+ autosetup_load_module $m eval $modsource(${m}.tcl)
+ } else {
+ set locs [list ${m}.tcl ${m}/init.tcl]
+ set found 0
+ foreach dir $dirs {
+ foreach loc $locs {
+ set source $dir/$loc
+ if {[file exists $source]} {
+ incr found
+ break
+ }
+ }
+ if {$found} {
+ break
+ }
+ }
+ if {$found} {
+ # For the convenience of the "use" source, point to the directory
+ # it is being loaded from
+ set ::usedir [file dirname $source]
+ autosetup_load_module $m source $source
+ autosetup_add_dep $source
+ } else {
+ autosetup-error "use: No such module: $m"
+ }
+ }
+ }
+}
+
+proc autosetup_load_auto_modules {} {
+ global autosetup modsource
+ # First load any embedded auto modules
+ foreach mod [array names modsource *.auto] {
+ autosetup_load_module $mod eval $modsource($mod)
+ }
+ # Now any external auto modules
+ foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
+ autosetup_load_module [file tail $file] source $file
+ }
+}
+
+# Load module source in the global scope by executing the given command
+proc autosetup_load_module {module args} {
+ global autosetup
+ set prev $autosetup(module)
+ set autosetup(module) $module
+
+ if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
+ autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
+ }
+ set autosetup(module) $prev
+}
+
+# Initial settings
+set autosetup(exe) $::argv0
+set autosetup(istcl) 1
+set autosetup(start) [clock millis]
+set autosetup(installed) 0
+set autosetup(sysinstall) 0
+set autosetup(msg-checking) 0
+set autosetup(msg-quiet) 0
+set autosetup(inittypes) {}
+set autosetup(module) autosetup
+
+# Embedded modules are inserted below here
+set autosetup(installed) 1
+set autosetup(sysinstall) 0
+# ----- @module asciidoc-formatting.tcl -----
+
+set modsource(asciidoc-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# asciidoc format
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " "
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc code {text} {
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc indent {text} {
+ puts " :: "
+ puts [para $text]
+}
+proc defn {first args} {
+ set sep ""
+ if {$first ne ""} {
+ puts "${first}::"
+ } else {
+ puts " :: "
+ }
+ set defn [string trim [join $args \n]]
+ regsub -all "\n\n" $defn "\n ::\n" defn
+ puts $defn
+}
+}
+
+# ----- @module formatting.tcl -----
+
+set modsource(formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides common text formatting
+
+# This is designed for documentation which looks like:
+# code {...}
+# or
+# code {
+# ...
+# ...
+# }
+# In the second case, we need to work out the indenting
+# and strip it from all lines but preserve the remaining indenting.
+# Note that all lines need to be indented with the same initial
+# spaces/tabs.
+#
+# Returns a list of lines with the indenting removed.
+#
+proc parse_code_block {text} {
+ # If the text begins with newline, take the following text,
+ # otherwise just return the original
+ if {![regexp "^\n(.*)" $text -> text]} {
+ return [list [string trim $text]]
+ }
+
+ # And trip spaces off the end
+ set text [string trimright $text]
+
+ set min 100
+ # Examine each line to determine the minimum indent
+ foreach line [split $text \n] {
+ if {$line eq ""} {
+ # Ignore empty lines for the indent calculation
+ continue
+ }
+ regexp "^(\[ \t\]*)" $line -> indent
+ set len [string length $indent]
+ if {$len < $min} {
+ set min $len
+ }
+ }
+
+ # Now make a list of lines with this indent removed
+ set lines {}
+ foreach line [split $text \n] {
+ lappend lines [string range $line $min end]
+ }
+
+ # Return the result
+ return $lines
+}
+}
+
+# ----- @module getopt.tcl -----
+
+set modsource(getopt.tcl) {
+# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Simple getopt module
+
+# Parse everything out of the argv list which looks like an option
+# Everything which doesn't look like an option, or is after --, is left unchanged
+# Understands --enable-xxx as a synonym for --xxx to enable the boolean option xxx.
+# Understands --disable-xxx to disable the boolean option xxx.
+#
+# The returned value is a dictionary keyed by option name
+# Each value is a list of {type value} ... where type is "bool" or "str".
+# The value for a boolean option is 0 or 1. The value of a string option is the value given.
+proc getopt {argvname} {
+ upvar $argvname argv
+ set nargv {}
+
+ set opts {}
+
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ set arg [lindex $argv $i]
+
+ #dputs arg=$arg
+
+ if {$arg eq "--"} {
+ # End of options
+ incr i
+ lappend nargv {*}[lrange $argv $i end]
+ break
+ }
+
+ if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
+ # --name=value
+ dict lappend opts $name [list str $value]
+ } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
+ if {$prefix in {enable- ""}} {
+ set value 1
+ } else {
+ set value 0
+ }
+ dict lappend opts $name [list bool $value]
+ } else {
+ lappend nargv $arg
+ }
+ }
+
+ #puts "getopt: argv=[join $argv] => [join $nargv]"
+ #array set getopt $opts
+ #parray getopt
+
+ set argv $nargv
+
+ return $opts
+}
+}
+
+# ----- @module help.tcl -----
+
+set modsource(help.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
+# All rights reserved
+
+# Module which provides usage, help and the command reference
+
+proc autosetup_help {what} {
+ use_pager
+
+ puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
+ puts "This is [autosetup_version], a build environment \"autoconfigurator\""
+ puts "See the documentation online at https://msteveb.github.io/autosetup/\n"
+
+ if {$what in {all local}} {
+ # Need to load auto.def now
+ if {[file exists $::autosetup(autodef)]} {
+ # Load auto.def as module "auto.def"
+ autosetup_load_module auto.def source $::autosetup(autodef)
+ }
+ if {$what eq "all"} {
+ set what *
+ } else {
+ set what auto.def
+ }
+ } else {
+ use $what
+ puts "Options for module $what:"
+ }
+ options-show $what
+ exit 0
+}
+
+proc autosetup_show_license {} {
+ global modsource autosetup
+ use_pager
+
+ if {[info exists modsource(LICENSE)]} {
+ puts $modsource(LICENSE)
+ return
+ }
+ foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
+ set path [file join $dir LICENSE]
+ if {[file exists $path]} {
+ puts [readfile $path]
+ return
+ }
+ }
+ puts "LICENSE not found"
+}
+
+# If not already paged and stdout is a tty, pipe the output through the pager
+# This is done by reinvoking autosetup with --nopager added
+proc use_pager {} {
+ if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
+ if {[catch {
+ exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& {*}[getenv PAGER] >@stdout <@stdin 2>@stderr
+ } msg opts] == 1} {
+ if {[dict get $opts -errorcode] eq "NONE"} {
+ # an internal/exec error
+ puts stderr $msg
+ exit 1
+ }
+ }
+ exit 0
+ }
+}
+
+# Outputs the autosetup references in one of several formats
+proc autosetup_reference {{type text}} {
+
+ use_pager
+
+ switch -glob -- $type {
+ wiki {use wiki-formatting}
+ ascii* {use asciidoc-formatting}
+ md - markdown {use markdown-formatting}
+ default {use text-formatting}
+ }
+
+ title "[autosetup_version] -- Command Reference"
+
+ section {Introduction}
+
+ p {
+ See https://msteveb.github.io/autosetup/ for the online documentation for 'autosetup'.
+ This documentation can also be accessed locally with `autosetup --ref`.
+ }
+
+ p {
+ 'autosetup' provides a number of built-in commands which
+ are documented below. These may be used from 'auto.def' to test
+ for features, define variables, create files from templates and
+ other similar actions.
+ }
+
+ automf_command_reference
+
+ exit 0
+}
+
+proc autosetup_output_block {type lines} {
+ if {[llength $lines]} {
+ switch $type {
+ section {
+ section $lines
+ }
+ subsection {
+ subsection $lines
+ }
+ code {
+ codelines $lines
+ }
+ p {
+ p [join $lines]
+ }
+ list {
+ foreach line $lines {
+ bullet $line
+ }
+ nl
+ }
+ }
+ }
+}
+
+# Generate a command reference from inline documentation
+proc automf_command_reference {} {
+ lappend files $::autosetup(prog)
+ lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
+
+ # We want to process all non-module files before module files
+ # and then modules in alphabetical order.
+ # So examine all files and extract docs into doc($modulename) and doc(_core_)
+ #
+ # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
+ # and $data is a string for section, subsection or a list of text lines for other types.
+
+ # XXX: Should commands be in alphabetical order too? Currently they are in file order.
+
+ set doc(_core_) {}
+ lappend doc(_core_) [list section "Core Commands"]
+
+ foreach file $files {
+ set modulename [file rootname [file tail $file]]
+ set current _core_
+ set f [open $file]
+ while {![eof $f]} {
+ set line [gets $f]
+
+ if {[regexp {^#.*@section (.*)$} $line -> section]} {
+ lappend doc($current) [list section $section]
+ continue
+ }
+
+ # Find embedded module names
+ if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
+ continue
+ }
+
+ # Find lines starting with "# @*" and continuing through the remaining comment lines
+ if {![regexp {^# @(.*)} $line -> cmd]} {
+ continue
+ }
+
+ # Synopsis or command?
+ if {$cmd eq "synopsis:"} {
+ set current $modulename
+ lappend doc($current) [list section "Module: $modulename"]
+ } else {
+ lappend doc($current) [list subsection $cmd]
+ }
+
+ set lines {}
+ set type p
+
+ # Now the description
+ while {![eof $f]} {
+ set line [gets $f]
+
+ if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
+ break
+ }
+ if {$hash eq "#"} {
+ set t code
+ } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
+ set t list
+ } else {
+ set t p
+ }
+
+ #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
+
+ if {$t ne $type || $cmd eq ""} {
+ # Finish the current block
+ lappend doc($current) [list $type $lines]
+ set lines {}
+ set type $t
+ }
+ if {$cmd ne ""} {
+ lappend lines $cmd
+ }
+ }
+
+ lappend doc($current) [list $type $lines]
+ }
+ close $f
+ }
+
+ # Now format and output the results
+
+ # _core_ will sort first
+ foreach module [lsort [array names doc]] {
+ foreach item $doc($module) {
+ autosetup_output_block {*}$item
+ }
+ }
+}
+}
+
+# ----- @module init.tcl -----
+
+set modsource(init.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module to help create auto.def and configure
+
+proc autosetup_init {type} {
+ set help 0
+ if {$type in {? help}} {
+ incr help
+ } elseif {![dict exists $::autosetup(inittypes) $type]} {
+ puts "Unknown type, --init=$type"
+ incr help
+ }
+ if {$help} {
+ puts "Use one of the following types (e.g. --init=make)\n"
+ foreach type [lsort [dict keys $::autosetup(inittypes)]] {
+ lassign [dict get $::autosetup(inittypes) $type] desc
+ # XXX: Use the options-show code to wrap the description
+ puts [format "%-10s %s" $type $desc]
+ }
+ return
+ }
+ lassign [dict get $::autosetup(inittypes) $type] desc script
+
+ puts "Initialising $type: $desc\n"
+
+ # All initialisations happens in the top level srcdir
+ cd $::autosetup(srcdir)
+
+ uplevel #0 $script
+}
+
+proc autosetup_add_init_type {type desc script} {
+ dict set ::autosetup(inittypes) $type [list $desc $script]
+}
+
+# This is for in creating build-system init scripts
+#
+# If the file doesn't exist, create it containing $contents
+# If the file does exist, only overwrite if --force is specified.
+#
+proc autosetup_check_create {filename contents} {
+ if {[file exists $filename]} {
+ if {!$::autosetup(force)} {
+ puts "I see $filename already exists."
+ return
+ } else {
+ puts "I will overwrite the existing $filename because you used --force."
+ }
+ } else {
+ puts "I don't see $filename, so I will create it."
+ }
+ writefile $filename $contents
+}
+}
+
+# ----- @module install.tcl -----
+
+set modsource(install.tcl) {
+# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which can install autosetup
+
+# autosetup(installed)=1 means that autosetup is not running from source
+# autosetup(sysinstall)=1 means that autosetup is running from a sysinstall version
+# shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
+
+proc autosetup_install {dir {shared 0}} {
+ global autosetup
+ if {$shared} {
+ if {$autosetup(installed) || $autosetup(sysinstall)} {
+ user-error "Can only --sysinstall from development sources"
+ }
+ } elseif {$autosetup(installed) && !$autosetup(sysinstall)} {
+ user-error "Can't --install from project install"
+ }
+
+ if {$autosetup(sysinstall)} {
+ # This is the sysinstall version, so install just uses references
+ cd $dir
+
+ puts "[autosetup_version] creating configure to use system-installed autosetup"
+ autosetup_create_configure 1
+ puts "Creating autosetup/README.autosetup"
+ file mkdir autosetup
+ autosetup_install_readme autosetup/README.autosetup 1
+ return
+ }
+
+ if {[catch {
+ if {$shared} {
+ set target $dir/bin/autosetup
+ set installedas $target
+ } else {
+ if {$dir eq "."} {
+ set installedas autosetup
+ } else {
+ set installedas $dir/autosetup
+ }
+ cd $dir
+ file mkdir autosetup
+ set target autosetup/autosetup
+ }
+ set targetdir [file dirname $target]
+ file mkdir $targetdir
+
+ set f [open $target w]
+
+ set publicmodules {}
+
+ # First the main script, but only up until "CUT HERE"
+ set in [open $autosetup(dir)/autosetup]
+ while {[gets $in buf] >= 0} {
+ if {$buf ne "##-- CUT HERE --##"} {
+ puts $f $buf
+ continue
+ }
+
+ # Insert the static modules here
+ # i.e. those which don't contain @synopsis:
+ # All modules are inserted if $shared is set
+ puts $f "set autosetup(installed) 1"
+ puts $f "set autosetup(sysinstall) $shared"
+ foreach file [lsort [glob $autosetup(libdir)/*.{tcl,auto}]] {
+ set modname [file tail $file]
+ set ext [file ext $modname]
+ set buf [readfile $file]
+ if {!$shared} {
+ if {$ext eq ".auto" || [string match "*\n# @synopsis:*" $buf]} {
+ lappend publicmodules $file
+ continue
+ }
+ }
+ dputs "install: importing lib/[file tail $file]"
+ puts $f "# ----- @module $modname -----"
+ puts $f "\nset modsource($modname) \{"
+ puts $f $buf
+ puts $f "\}\n"
+ }
+ if {$shared} {
+ foreach {srcname destname} [list $autosetup(libdir)/README.autosetup-lib README.autosetup \
+ $autosetup(srcdir)/LICENSE LICENSE] {
+ dputs "install: importing $srcname as $destname"
+ puts $f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
+ }
+ }
+ }
+ close $in
+ close $f
+ catch {exec chmod 755 $target}
+
+ set installfiles {autosetup-config.guess autosetup-config.sub autosetup-test-tclsh}
+ set removefiles {}
+
+ if {!$shared} {
+ autosetup_install_readme $targetdir/README.autosetup 0
+
+ # Install public modules
+ foreach file $publicmodules {
+ set tail [file tail $file]
+ autosetup_install_file $file $targetdir/$tail
+ }
+ lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
+ lappend removefiles config.guess config.sub test-tclsh find-tclsh
+ } else {
+ lappend installfiles {sys-find-tclsh autosetup-find-tclsh}
+ }
+
+ # Install support files
+ foreach fileinfo $installfiles {
+ if {[llength $fileinfo] == 2} {
+ lassign $fileinfo source dest
+ } else {
+ lassign $fileinfo source
+ set dest $source
+ }
+ autosetup_install_file $autosetup(dir)/$source $targetdir/$dest
+ }
+
+ # Remove obsolete files
+ foreach file $removefiles {
+ if {[file exists $targetdir/$file]} {
+ file delete $targetdir/$file
+ }
+ }
+ } error]} {
+ user-error "Failed to install autosetup: $error"
+ }
+ if {$shared} {
+ set type "system"
+ } else {
+ set type "local"
+ }
+ puts "Installed $type [autosetup_version] to $installedas"
+
+ if {!$shared} {
+ # Now create 'configure' if necessary
+ autosetup_create_configure 0
+ }
+}
+
+proc autosetup_create_configure {shared} {
+ if {[file exists configure]} {
+ if {!$::autosetup(force)} {
+ # Could this be an autosetup configure?
+ if {![string match "*\nWRAPPER=*" [readfile configure]]} {
+ puts "I see configure, but not created by autosetup, so I won't overwrite it."
+ puts "Remove it or use --force to overwrite."
+ return
+ }
+ } else {
+ puts "I will overwrite the existing configure because you used --force."
+ }
+ } else {
+ puts "I don't see configure, so I will create it."
+ }
+ if {$shared} {
+ writefile configure \
+{#!/bin/sh
+WRAPPER="$0"; export WRAPPER; "autosetup" "$@"
+}
+ } else {
+ writefile configure \
+{#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+#@@INITCHECK@@#
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
+}
+ }
+ catch {exec chmod 755 configure}
+}
+
+# Append the contents of $file to filehandle $f
+proc autosetup_install_append {f file} {
+ dputs "install: include $file"
+ set in [open $file]
+ puts $f [read $in]
+ close $in
+}
+
+proc autosetup_install_file {source target} {
+ dputs "install: $source => $target"
+ if {![file exists $source]} {
+ error "Missing installation file '$source'"
+ }
+ writefile $target [readfile $source]\n
+ # If possible, copy the file mode
+ file stat $source stat
+ set mode [format %o [expr {$stat(mode) & 0x1ff}]]
+ catch {exec chmod $mode $target}
+}
+
+proc autosetup_install_readme {target sysinstall} {
+ set readme "README.autosetup created by [autosetup_version]\n\n"
+ if {$sysinstall} {
+ append readme \
+{This is the autosetup directory for a system install of autosetup.
+Loadable modules can be added here.
+}
+ } else {
+ append readme \
+{This is the autosetup directory for a local install of autosetup.
+It contains autosetup, support files and loadable modules.
+}
+}
+
+ append readme {
+*.tcl files in this directory are optional modules which
+can be loaded with the 'use' directive.
+
+*.auto files in this directory are auto-loaded.
+
+For more information, see https://msteveb.github.io/autosetup/
+}
+ dputs "install: autosetup/README.autosetup"
+ writefile $target $readme
+}
+}
+
+# ----- @module markdown-formatting.tcl -----
+
+set modsource(markdown-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# markdown format (kramdown syntax)
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " " text
+ regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
+ regsub -all {^'([^']*)'} $text {**`\1`**} text
+ regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
+ return $text
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc codelines {lines} {
+ puts "~~~~~~~~~~~~"
+ foreach line $lines {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc code {text} {
+ puts "~~~~~~~~~~~~"
+ foreach line [parse_code_block $text] {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ puts "### `$text`"
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc defn {first args} {
+ puts "^"
+ set defn [string trim [join $args \n]]
+ if {$first ne ""} {
+ puts "**${first}**"
+ puts -nonewline ": "
+ regsub -all "\n\n" $defn "\n: " defn
+ }
+ puts "$defn"
+}
+}
+
+# ----- @module misc.tcl -----
+
+set modsource(misc.tcl) {
+# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module containing misc procs useful to modules
+# Largely for platform compatibility
+
+set autosetup(istcl) [info exists ::tcl_library]
+set autosetup(iswin) [string equal windows $tcl_platform(platform)]
+
+if {$autosetup(iswin)} {
+ # mingw/windows separates $PATH with semicolons
+ # and doesn't have an executable bit
+ proc split-path {} {
+ split [getenv PATH .] {;}
+ }
+ proc file-isexec {exec} {
+ # Basic test for windows. We ignore .bat
+ if {[file isfile $exec] || [file isfile $exec.exe]} {
+ return 1
+ }
+ return 0
+ }
+} else {
+ # unix separates $PATH with colons and has and executable bit
+ proc split-path {} {
+ split [getenv PATH .] :
+ }
+ # Check for an executable file
+ proc file-isexec {exec} {
+ if {[file executable $exec] && [file isfile $exec]} {
+ return 1
+ }
+ return 0
+ }
+}
+
+# Assume that exec can return stdout and stderr
+proc exec-with-stderr {args} {
+ exec {*}$args 2>@1
+}
+
+if {$autosetup(istcl)} {
+ # Tcl doesn't have the env command
+ proc getenv {name args} {
+ if {[info exists ::env($name)]} {
+ return $::env($name)
+ }
+ if {[llength $args]} {
+ return [lindex $args 0]
+ }
+ return -code error "environment variable \"$name\" does not exist"
+ }
+ proc isatty? {channel} {
+ dict exists [fconfigure $channel] -xchar
+ }
+ # Jim-compatible stacktrace using info frame
+ proc stacktrace {} {
+ set stacktrace {}
+ # 2 to skip the current frame
+ for {set i 2} {$i < [info frame]} {incr i} {
+ set frame [info frame -$i]
+ if {[dict exists $frame file]} {
+ # We don't need proc, so use ""
+ lappend stacktrace "" [dict get $frame file] [dict get $frame line]
+ }
+ }
+ return $stacktrace
+ }
+} else {
+ if {$autosetup(iswin)} {
+ # On Windows, backslash convert all environment variables
+ # (Assume that Tcl does this for us)
+ proc getenv {name args} {
+ string map {\\ /} [env $name {*}$args]
+ }
+ } else {
+ # Jim on unix is simple
+ alias getenv env
+ }
+ proc isatty? {channel} {
+ set tty 0
+ catch {
+ # isatty is a recent addition to Jim Tcl
+ set tty [$channel isatty]
+ }
+ return $tty
+ }
+}
+
+# In case 'file normalize' doesn't exist
+#
+proc file-normalize {path} {
+ if {[catch {file normalize $path} result]} {
+ if {$path eq ""} {
+ return ""
+ }
+ set oldpwd [pwd]
+ if {[file isdir $path]} {
+ cd $path
+ set result [pwd]
+ } else {
+ cd [file dirname $path]
+ set result [file join [pwd] [file tail $path]]
+ }
+ cd $oldpwd
+ }
+ return $result
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-location {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ foreach {p f l} [stacktrace] {
+ if {[string match *.def $f]} {
+ return "[relative-path $f]:$l: Error: $msg"
+ }
+ #puts "Skipping $f:$l"
+ }
+ return $msg
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-stacktrace {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ for {set i 1} {$i < [info level]} {incr i} {
+ if {$::autosetup(istcl)} {
+ array set info [info frame -$i]
+ } else {
+ lassign [info frame -$i] info(caller) info(file) info(line)
+ }
+ if {[string match *.def $info(file)]} {
+ return "[relative-path $info(file)]:$info(line): Error: $msg"
+ }
+ #puts "Skipping $info(file):$info(line)"
+ }
+ return $msg
+}
+
+# Given the return from [catch {...} msg opts], returns an appropriate
+# error message. A nice one for Jim and a less-nice one for Tcl.
+# If 'fulltrace' is set, a full stack trace is provided.
+# Otherwise a simple message is provided.
+#
+# This is designed for developer errors, e.g. in module code or auto.def code
+#
+#
+proc error-dump {msg opts fulltrace} {
+ if {$::autosetup(istcl)} {
+ if {$fulltrace} {
+ return "Error: [dict get $opts -errorinfo]"
+ } else {
+ return "Error: $msg"
+ }
+ } else {
+ lassign $opts(-errorinfo) p f l
+ if {$f ne ""} {
+ set result "$f:$l: Error: "
+ }
+ append result "$msg\n"
+ if {$fulltrace} {
+ append result [stackdump $opts(-errorinfo)]
+ }
+
+ # Remove the trailing newline
+ string trim $result
+ }
+}
+}
+
+# ----- @module text-formatting.tcl -----
+
+set modsource(text-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+
+use formatting
+
+proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
+ set len 0
+ set space $firstprefix
+
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word eq ""} {
+ continue
+ }
+ if {[info exists partial]} {
+ append partial " " $word
+ if {[string first $quote $word] < 0} {
+ # Haven't found end of quoted word
+ continue
+ }
+ # Finished quoted word
+ set word $partial
+ unset partial
+ unset quote
+ } else {
+ set quote [string index $word 0]
+ if {$quote in {' *}} {
+ if {[string first $quote $word 1] < 0} {
+ # Haven't found end of quoted word
+ # Not a whole word.
+ set first [string index $word 0]
+ # Start of quoted word
+ set partial $word
+ continue
+ }
+ }
+ }
+
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+
+ # Use man-page conventions for highlighting 'quoted' and *quoted*
+ # single words.
+ # Use x^Hx for *bold* and _^Hx for 'underline'.
+ #
+ # less and more will both understand this.
+ # Pipe through 'col -b' to remove them.
+ if {[regexp {^'(.*)'(.*)} $word -> quoted after]} {
+ set quoted [string map {~ " "} $quoted]
+ regsub -all . $quoted "&\b&" quoted
+ set word $quoted$after
+ } elseif {[regexp {^[*](.*)[*](.*)} $word -> quoted after]} {
+ set quoted [string map {~ " "} $quoted]
+ regsub -all . $quoted "_\b&" quoted
+ set word $quoted$after
+ }
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {[info exists partial]} {
+ # Missing end of quote
+ puts -nonewline $space$partial
+ }
+ if {$len} {
+ puts ""
+ }
+}
+proc title {text} {
+ underline [string trim $text] =
+ nl
+}
+proc p {text} {
+ wordwrap $text 80
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[string trim $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ wordwrap $text 76 " * " " "
+}
+proc indent {text} {
+ wordwrap $text 76 " " " "
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ underline " $first" ~
+ }
+ foreach p $args {
+ if {$p ne ""} {
+ indent $p
+ }
+ }
+}
+}
+
+# ----- @module util.tcl -----
+
+set modsource(util.tcl) {
+# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which contains miscellaneous utility functions
+
+# @section Utilities
+
+# @compare-versions version1 version2
+#
+# Versions are of the form 'a.b.c' (may be any number of numeric components)
+#
+# Compares the two versions and returns:
+## -1 if v1 < v2
+## 0 if v1 == v2
+## 1 if v1 > v2
+#
+# If one version has fewer components than the other, 0 is substituted to the right. e.g.
+## 0.2 < 0.3
+## 0.2.5 > 0.2
+## 1.1 == 1.1.0
+#
+proc compare-versions {v1 v2} {
+ foreach c1 [split $v1 .] c2 [split $v2 .] {
+ if {$c1 eq ""} {
+ set c1 0
+ }
+ if {$c2 eq ""} {
+ set c2 0
+ }
+ if {$c1 < $c2} {
+ return -1
+ }
+ if {$c1 > $c2} {
+ return 1
+ }
+ }
+ return 0
+}
+
+# @suffix suf list
+#
+# Takes a list and returns a new list with '$suf' appended
+# to each element
+#
+## suffix .c {a b c} => {a.c b.c c.c}
+#
+proc suffix {suf list} {
+ set result {}
+ foreach p $list {
+ lappend result $p$suf
+ }
+ return $result
+}
+
+# @prefix pre list
+#
+# Takes a list and returns a new list with '$pre' prepended
+# to each element
+#
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
+#
+proc prefix {pre list} {
+ set result {}
+ foreach p $list {
+ lappend result $pre$p
+ }
+ return $result
+}
+
+# @lpop list
+#
+# Removes the last entry from the given list and returns it.
+proc lpop {listname} {
+ upvar $listname list
+ set val [lindex $list end]
+ set list [lrange $list 0 end-1]
+ return $val
+}
+}
+
+# ----- @module wiki-formatting.tcl -----
+
+set modsource(wiki-formatting.tcl) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# wiki.tcl.tk format output
+
+use formatting
+
+proc joinlines {text} {
+ set lines {}
+ foreach l [split [string trim $text] \n] {
+ lappend lines [string trim $l]
+ }
+ join $lines
+}
+proc p {text} {
+ puts [joinlines $text]
+ puts ""
+}
+proc title {text} {
+ puts "*** [joinlines $text] ***"
+ puts ""
+}
+proc codelines {lines} {
+ puts "======"
+ foreach line $lines {
+ puts " $line"
+ }
+ puts "======"
+}
+proc code {text} {
+ puts "======"
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ puts "======"
+}
+proc nl {} {
+}
+proc section {text} {
+ puts "'''$text'''"
+ puts ""
+}
+proc subsection {text} {
+ puts "''$text''"
+ puts ""
+}
+proc bullet {text} {
+ puts " * [joinlines $text]"
+}
+proc indent {text} {
+ puts " : [joinlines $text]"
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ indent '''$first'''
+ }
+
+ foreach p $args {
+ p $p
+ }
+}
+}
+
+
+##################################################################
+#
+# Entry/Exit
+#
+if {$autosetup(debug)} {
+ main $argv
+}
+if {[catch {main $argv} msg opts] == 1} {
+ show-notices
+ autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
+ if {!$autosetup(debug)} {
+ puts stderr "Try: '[file tail $autosetup(exe)] --autosetup-debug' for a full stack trace"
+ }
+ exit 1
+}
diff --git a/config.guess b/autosetup/autosetup-config.guess
old mode 100644
new mode 100755
similarity index 64%
rename from config.guess
rename to autosetup/autosetup-config.guess
index ae713942d8..48a684601b
--- a/config.guess
+++ b/autosetup/autosetup-config.guess
@@ -1,12 +1,14 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2019 Free Software Foundation, Inc.
+# Copyright 1992-2024 Free Software Foundation, Inc.
-timestamp='2019-05-28'
+# shellcheck disable=SC2006,SC2268 # see below for rationale
+
+timestamp='2024-07-27'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
+# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -27,17 +29,25 @@ timestamp='2019-05-28'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to .
+# The "shellcheck disable" line above the timestamp inhibits complaints
+# about features and limitations of the classic Bourne shell that were
+# superseded or lifted in POSIX. However, this script identifies a wide
+# variety of pre-POSIX systems that do not have POSIX shells at all, and
+# even some reasonably current systems (Solaris 10 as case-in-point) still
+# have a pre-POSIX /bin/sh.
+
+
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION]
-Output the configuration name of the system \`$me' is run on.
+Output the configuration name of the system '$me' is run on.
Options:
-h, --help print this help, then exit
@@ -50,13 +60,13 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2019 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
-Try \`$me --help' for more information."
+Try '$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
@@ -84,13 +94,16 @@ if test $# != 0; then
exit 1
fi
+# Just in case it came from the environment.
+GUESS=
+
# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
# temporary files to be created and, as you can see below, it is a
# headache to deal with in a portable fashion.
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
+# Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still
+# use 'HOST_CC' if defined, but it is deprecated.
# Portable tmp directory creation inspired by the Autoconf team.
@@ -99,8 +112,10 @@ tmp=
trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
set_cc_for_build() {
+ # prevent multiple calls if $tmp is already set
+ test "$tmp" && return 0
: "${TMPDIR=/tmp}"
- # shellcheck disable=SC2039
+ # shellcheck disable=SC2039,SC3028
{ tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
@@ -108,9 +123,9 @@ set_cc_for_build() {
dummy=$tmp/dummy
case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
,,) echo "int x;" > "$dummy.c"
- for driver in cc gcc c89 c99 ; do
+ for driver in cc gcc c17 c99 c89 ; do
if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$driver"
+ CC_FOR_BUILD=$driver
break
fi
done
@@ -131,40 +146,57 @@ fi
UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-case "$UNAME_SYSTEM" in
+case $UNAME_SYSTEM in
Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
+ LIBC=unknown
set_cc_for_build
cat <<-EOF > "$dummy.c"
+ #if defined(__ANDROID__)
+ LIBC=android
+ #else
#include
#if defined(__UCLIBC__)
LIBC=uclibc
#elif defined(__dietlibc__)
LIBC=dietlibc
- #else
+ #elif defined(__GLIBC__)
LIBC=gnu
+ #elif defined(__LLVM_LIBC__)
+ LIBC=llvm
+ #else
+ #include
+ /* First heuristic to detect musl libc. */
+ #ifdef __DEFINED_va_list
+ LIBC=musl
+ #endif
+ #endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+ cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ eval "$cc_set_libc"
- # If ldd exists, use it to detect musl libc.
- if command -v ldd >/dev/null && \
- ldd --version 2>&1 | grep -q ^musl
- then
- LIBC=musl
+ # Second heuristic to detect musl libc.
+ if [ "$LIBC" = unknown ] &&
+ command -v ldd >/dev/null &&
+ ldd --version 2>&1 | grep -q ^musl; then
+ LIBC=musl
+ fi
+
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ if [ "$LIBC" = unknown ]; then
+ LIBC=gnu
fi
;;
esac
# Note: order is significant - the case branches are not exclusive.
-case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -176,12 +208,12 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
#
# Note: NetBSD doesn't particularly care about the vendor
# portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
- "/sbin/$sysctl" 2>/dev/null || \
- "/usr/sbin/$sysctl" 2>/dev/null || \
+ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
echo unknown)`
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
+ aarch64eb) machine=aarch64_be-unknown ;;
armeb) machine=armeb-unknown ;;
arm*) machine=arm-unknown ;;
sh3el) machine=shl-unknown ;;
@@ -190,13 +222,13 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
earmv*)
arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
- machine="${arch}${endian}"-unknown
+ machine=${arch}${endian}-unknown
;;
- *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ *) machine=$UNAME_MACHINE_ARCH-unknown ;;
esac
# The Operating System including object format, if it has switched
# to ELF recently (or will in the future) and ABI.
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
earm*)
os=netbsdelf
;;
@@ -217,7 +249,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
;;
esac
# Determine ABI tags.
- case "$UNAME_MACHINE_ARCH" in
+ case $UNAME_MACHINE_ARCH in
earm*)
expr='s/^earmv[0-9]/-eabi/;s/eb$//'
abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
@@ -228,7 +260,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# thus, need a distinct triplet. However, they do not need
# kernel version information, so it can be replaced with a
# suitable tag, in the style of linux-gnu.
- case "$UNAME_VERSION" in
+ case $UNAME_VERSION in
Debian*)
release='-gnu'
;;
@@ -239,45 +271,57 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
# contains redundant information, the shorter form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "$machine-${os}${release}${abi-}"
- exit ;;
+ GUESS=$machine-${os}${release}${abi-}
+ ;;
*:Bitrig:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+ ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+ ;;
+ *:SecBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+ GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+ ;;
*:LibertyBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
- echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+ ;;
*:MidnightBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+ ;;
*:ekkoBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+ ;;
*:SolidBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+ ;;
+ *:OS108:*:*)
+ GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+ ;;
macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:MirBSD:*:*)
- echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+ ;;
*:Sortix:*:*)
- echo "$UNAME_MACHINE"-unknown-sortix
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sortix
+ ;;
+ *:Twizzler:*:*)
+ GUESS=$UNAME_MACHINE-unknown-twizzler
+ ;;
*:Redox:*:*)
- echo "$UNAME_MACHINE"-unknown-redox
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-redox
+ ;;
mips:OSF1:*.*)
- echo mips-dec-osf1
- exit ;;
+ GUESS=mips-dec-osf1
+ ;;
alpha:OSF1:*:*)
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ trap '' 0
case $UNAME_RELEASE in
*4.0)
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
@@ -291,7 +335,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# covers most systems running today. This code pipes the CPU
# types through head -n 1, so we only detect the type of CPU 0.
ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
- case "$ALPHA_CPU_TYPE" in
+ case $ALPHA_CPU_TYPE in
"EV4 (21064)")
UNAME_MACHINE=alpha ;;
"EV4.5 (21064)")
@@ -328,117 +372,121 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# A Tn.n version is a released field test version.
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
- echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
- # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
- exitcode=$?
- trap '' 0
- exit $exitcode ;;
+ OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+ ;;
Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
+ GUESS=m68k-unknown-sysv4
+ ;;
*:[Aa]miga[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-amigaos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-amigaos
+ ;;
*:[Mm]orph[Oo][Ss]:*:*)
- echo "$UNAME_MACHINE"-unknown-morphos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-morphos
+ ;;
*:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
+ GUESS=i370-ibm-openedition
+ ;;
*:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
+ GUESS=s390-ibm-zvmoe
+ ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
+ GUESS=powerpc-ibm-os400
+ ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix"$UNAME_RELEASE"
- exit ;;
+ GUESS=arm-acorn-riscix$UNAME_RELEASE
+ ;;
arm*:riscos:*:*|arm*:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
+ GUESS=arm-unknown-riscos
+ ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
+ GUESS=hppa1.1-hitachi-hiuxmpp
+ ;;
Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
+ case `(/bin/universe) 2>/dev/null` in
+ att) GUESS=pyramid-pyramid-sysv3 ;;
+ *) GUESS=pyramid-pyramid-bsd ;;
+ esac
+ ;;
NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
+ GUESS=pyramid-pyramid-svr4
+ ;;
DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
+ GUESS=sparc-icl-nx6
+ ;;
DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
+ sparc) GUESS=sparc-icl-nx7 ;;
+ esac
+ ;;
s390x:SunOS:*:*)
- echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+ ;;
sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-hal-solaris2$SUN_REL
+ ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris2$SUN_REL
+ ;;
i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
- echo i386-pc-auroraux"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-pc-auroraux$UNAME_RELEASE
+ ;;
i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
set_cc_for_build
SUN_ARCH=i386
# If there is a compiler, see if it is configured for 64-bit objects.
# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
# This test works for both compilers.
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
then
SUN_ARCH=x86_64
fi
fi
- echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+ ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
# SunOS6. Hard to guess exactly what SunOS6 will be like, but
# it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=sparc-sun-solaris3$SUN_REL
+ ;;
sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
+ case `/usr/bin/arch -k` in
Series*|S4*)
UNAME_RELEASE=`uname -v`
;;
esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
- exit ;;
+ # Japanese Language versions have a version number like '4.1.3-JL'.
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+ GUESS=sparc-sun-sunos$SUN_REL
+ ;;
sun3*:SunOS:*:*)
- echo m68k-sun-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
+ ;;
sun*:*:4.2BSD:*)
UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
- case "`/bin/arch`" in
+ case `/bin/arch` in
sun3)
- echo m68k-sun-sunos"$UNAME_RELEASE"
+ GUESS=m68k-sun-sunos$UNAME_RELEASE
;;
sun4)
- echo sparc-sun-sunos"$UNAME_RELEASE"
+ GUESS=sparc-sun-sunos$UNAME_RELEASE
;;
esac
- exit ;;
+ ;;
aushp:SunOS:*:*)
- echo sparc-auspex-sunos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-auspex-sunos$UNAME_RELEASE
+ ;;
# The situation for MiNT is a little confusing. The machine name
# can be virtually everything (everything which is not
# "atarist" or "atariste" at least should have a processor
@@ -448,41 +496,41 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-atari-mint$UNAME_RELEASE
+ ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-milan-mint$UNAME_RELEASE
+ ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-hades-mint$UNAME_RELEASE
+ ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-mint$UNAME_RELEASE
+ ;;
m68k:machten:*:*)
- echo m68k-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-machten$UNAME_RELEASE
+ ;;
powerpc:machten:*:*)
- echo powerpc-apple-machten"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-machten$UNAME_RELEASE
+ ;;
RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
+ GUESS=mips-dec-mach_bsd4.3
+ ;;
RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dec-ultrix$UNAME_RELEASE
+ ;;
VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix"$UNAME_RELEASE"
- exit ;;
+ GUESS=vax-dec-ultrix$UNAME_RELEASE
+ ;;
2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix"$UNAME_RELEASE"
- exit ;;
+ GUESS=clipper-intergraph-clix$UNAME_RELEASE
+ ;;
mips:*:*:UMIPS | mips:*:*:RISCos)
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -510,82 +558,84 @@ EOF
dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-mips-riscos$UNAME_RELEASE
+ ;;
Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
+ GUESS=powerpc-motorola-powermax
+ ;;
Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
+ GUESS=powerpc-harris-powermax
+ ;;
Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
+ GUESS=powerpc-harris-powerunix
+ ;;
m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
+ GUESS=m88k-harris-cxux7
+ ;;
m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
+ GUESS=m88k-motorola-sysv4
+ ;;
m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
AViiON:dgux:*:*)
# DG/UX returns AViiON for all architectures
UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
then
- if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
- [ "$TARGET_BINARY_INTERFACE"x = x ]
+ if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+ test "$TARGET_BINARY_INTERFACE"x = x
then
- echo m88k-dg-dgux"$UNAME_RELEASE"
+ GUESS=m88k-dg-dgux$UNAME_RELEASE
else
- echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
fi
else
- echo i586-dg-dgux"$UNAME_RELEASE"
+ GUESS=i586-dg-dgux$UNAME_RELEASE
fi
- exit ;;
+ ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
+ GUESS=m88k-dolphin-sysv3
+ ;;
M88*:*:R3*:*)
# Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
+ GUESS=m88k-motorola-sysv3
+ ;;
XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
+ GUESS=m88k-tektronix-sysv3
+ ;;
Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
+ GUESS=m68k-tektronix-bsd
+ ;;
*:IRIX*:*:*)
- echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
- exit ;;
+ IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+ GUESS=mips-sgi-irix$IRIX_REL
+ ;;
????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ ;; # Note that: echo "'`uname -s`'" gives 'AIX '
i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
+ GUESS=i386-ibm-aix
+ ;;
ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
+ if test -x /usr/bin/oslevel ; then
IBM_REV=`/usr/bin/oslevel`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+ ;;
*:AIX:2:3)
if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
#include
- main()
+ int
+ main ()
{
if (!__power_pc())
exit(1);
@@ -595,16 +645,16 @@ EOF
EOF
if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
then
- echo "$SYSTEM_NAME"
+ GUESS=$SYSTEM_NAME
else
- echo rs6000-ibm-aix3.2.5
+ GUESS=rs6000-ibm-aix3.2.5
fi
elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
+ GUESS=rs6000-ibm-aix3.2.4
else
- echo rs6000-ibm-aix3.2
+ GUESS=rs6000-ibm-aix3.2
fi
- exit ;;
+ ;;
*:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
@@ -612,56 +662,56 @@ EOF
else
IBM_ARCH=powerpc
fi
- if [ -x /usr/bin/lslpp ] ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ if test -x /usr/bin/lslpp ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
else
- IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
fi
- echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
- exit ;;
+ GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+ ;;
*:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
+ GUESS=rs6000-ibm-aix
+ ;;
ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
+ GUESS=romp-ibm-bsd4.4
+ ;;
ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
+ GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to
+ ;; # report: romp-ibm BSD 4.3
*:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
+ GUESS=rs6000-bull-bosx
+ ;;
DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
+ GUESS=m68k-bull-sysv3
+ ;;
9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
+ GUESS=m68k-hp-bsd
+ ;;
hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
+ GUESS=m68k-hp-bsd4.4
+ ;;
9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
- case "$UNAME_MACHINE" in
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ case $UNAME_MACHINE in
9000/31?) HP_ARCH=m68000 ;;
9000/[34]??) HP_ARCH=m68k ;;
9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
+ if test -x /usr/bin/getconf; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "$sc_cpu_version" in
+ case $sc_cpu_version in
523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
532) # CPU_PA_RISC2_0
- case "$sc_kernel_bits" in
+ case $sc_kernel_bits in
32) HP_ARCH=hppa2.0n ;;
64) HP_ARCH=hppa2.0w ;;
'') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
esac ;;
esac
fi
- if [ "$HP_ARCH" = "" ]; then
+ if test "$HP_ARCH" = ""; then
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -669,7 +719,8 @@ EOF
#include
#include
- int main ()
+ int
+ main ()
{
#if defined(_SC_KERNEL_BITS)
long bits = sysconf(_SC_KERNEL_BITS);
@@ -700,7 +751,7 @@ EOF
test -z "$HP_ARCH" && HP_ARCH=hppa
fi ;;
esac
- if [ "$HP_ARCH" = hppa2.0w ]
+ if test "$HP_ARCH" = hppa2.0w
then
set_cc_for_build
@@ -721,12 +772,12 @@ EOF
HP_ARCH=hppa64
fi
fi
- echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
- exit ;;
+ GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+ ;;
ia64:HP-UX:*:*)
- HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux"$HPUX_REV"
- exit ;;
+ HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+ GUESS=ia64-hp-hpux$HPUX_REV
+ ;;
3050*:HI-UX:*:*)
set_cc_for_build
sed 's/^ //' << EOF > "$dummy.c"
@@ -756,36 +807,36 @@ EOF
EOF
$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
+ GUESS=unknown-hitachi-hiuxwe2
+ ;;
9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
- echo hppa1.1-hp-bsd
- exit ;;
+ GUESS=hppa1.1-hp-bsd
+ ;;
9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
+ GUESS=hppa1.0-hp-bsd
+ ;;
*9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
+ GUESS=hppa1.0-hp-mpeix
+ ;;
hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
- echo hppa1.1-hp-osf
- exit ;;
+ GUESS=hppa1.1-hp-osf
+ ;;
hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
+ GUESS=hppa1.0-hp-osf
+ ;;
i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo "$UNAME_MACHINE"-unknown-osf1mk
+ if test -x /usr/sbin/sysversion ; then
+ GUESS=$UNAME_MACHINE-unknown-osf1mk
else
- echo "$UNAME_MACHINE"-unknown-osf1
+ GUESS=$UNAME_MACHINE-unknown-osf1
fi
- exit ;;
+ ;;
parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
+ GUESS=hppa1.1-hp-lites
+ ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
+ GUESS=c1-convex-bsd
+ ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
@@ -793,17 +844,18 @@ EOF
fi
exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
+ GUESS=c34-convex-bsd
+ ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
+ GUESS=c38-convex-bsd
+ ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
+ GUESS=c4-convex-bsd
+ ;;
CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=ymp-cray-unicos$CRAY_REL
+ ;;
CRAY*[A-Z]90:*:*:*)
echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -811,114 +863,155 @@ EOF
-e 's/\.[^.]*$/.X/'
exit ;;
CRAY*TS:*:*:*)
- echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=t90-cray-unicos$CRAY_REL
+ ;;
CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=alphaev5-cray-unicosmk$CRAY_REL
+ ;;
CRAY*SV1:*:*:*)
- echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=sv1-cray-unicos$CRAY_REL
+ ;;
*:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
- exit ;;
+ CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+ GUESS=craynv-cray-unicosmp$CRAY_REL
+ ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+ ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+ ;;
sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+ ;;
*:BSD/OS:*:*)
- echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+ ;;
arm:FreeBSD:*:*)
UNAME_PROCESSOR=`uname -p`
set_cc_for_build
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
else
- echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
fi
- exit ;;
+ ;;
*:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- case "$UNAME_PROCESSOR" in
+ UNAME_PROCESSOR=`uname -p`
+ case $UNAME_PROCESSOR in
amd64)
UNAME_PROCESSOR=x86_64 ;;
i386)
UNAME_PROCESSOR=i586 ;;
esac
- echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
- exit ;;
+ FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+ ;;
i*:CYGWIN*:*)
- echo "$UNAME_MACHINE"-pc-cygwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-cygwin
+ ;;
*:MINGW64*:*)
- echo "$UNAME_MACHINE"-pc-mingw64
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw64
+ ;;
*:MINGW*:*)
- echo "$UNAME_MACHINE"-pc-mingw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-mingw32
+ ;;
*:MSYS*:*)
- echo "$UNAME_MACHINE"-pc-msys
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msys
+ ;;
i*:PW*:*)
- echo "$UNAME_MACHINE"-pc-pw32
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-pw32
+ ;;
+ *:SerenityOS:*:*)
+ GUESS=$UNAME_MACHINE-pc-serenity
+ ;;
*:Interix*:*)
- case "$UNAME_MACHINE" in
+ case $UNAME_MACHINE in
x86)
- echo i586-pc-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=i586-pc-interix$UNAME_RELEASE
+ ;;
authenticamd | genuineintel | EM64T)
- echo x86_64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=x86_64-unknown-interix$UNAME_RELEASE
+ ;;
IA64)
- echo ia64-unknown-interix"$UNAME_RELEASE"
- exit ;;
+ GUESS=ia64-unknown-interix$UNAME_RELEASE
+ ;;
esac ;;
i*:UWIN*:*)
- echo "$UNAME_MACHINE"-pc-uwin
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-uwin
+ ;;
amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-pc-cygwin
- exit ;;
+ GUESS=x86_64-pc-cygwin
+ ;;
prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
- exit ;;
+ SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+ GUESS=powerpcle-unknown-solaris2$SUN_REL
+ ;;
*:GNU:*:*)
# the GNU system
- echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
- exit ;;
+ GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+ GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+ ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
- exit ;;
+ GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+ GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+ ;;
+ x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-pc-managarm-mlibc"
+ ;;
+ *:[Mm]anagarm:*:*)
+ GUESS="$UNAME_MACHINE-unknown-managarm-mlibc"
+ ;;
*:Minix:*:*)
- echo "$UNAME_MACHINE"-unknown-minix
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-minix
+ ;;
aarch64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __ARM_EABI__
+ #ifdef __ARM_PCS_VFP
+ ABI=eabihf
+ #else
+ ABI=eabi
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;;
+ esac
+ fi
+ GUESS=$CPU-unknown-linux-$LIBCABI
+ ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
EV5) UNAME_MACHINE=alphaev5 ;;
EV56) UNAME_MACHINE=alphaev56 ;;
PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -929,60 +1022,72 @@ EOF
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
arm*:Linux:*:*)
set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
else
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
fi
fi
- exit ;;
+ ;;
avr32*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
cris:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
crisv32:Linux:*:*)
- echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+ ;;
e2k:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
frv:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
hexagon:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+ ;;
ia64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
k1om:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
+ kvx:cos:*:*)
+ GUESS=$UNAME_MACHINE-unknown-cos
+ ;;
+ kvx:mbr:*:*)
+ GUESS=$UNAME_MACHINE-unknown-mbr
+ ;;
+ loongarch32:Linux:*:* | loongarch64:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m32r*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
m68*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
mips:Linux:*:* | mips64:Linux:*:*)
set_cc_for_build
IS_GLIBC=0
@@ -1027,113 +1132,135 @@ EOF
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+ cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+ eval "$cc_set_vars"
test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
;;
mips64el:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
openrisc*:Linux:*:*)
- echo or1k-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=or1k-unknown-linux-$LIBC
+ ;;
or32:Linux:*:* | or1k*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=sparc-unknown-linux-$LIBC
+ ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=hppa64-unknown-linux-$LIBC
+ ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
- PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
- *) echo hppa-unknown-linux-"$LIBC" ;;
+ PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+ PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+ *) GUESS=hppa-unknown-linux-$LIBC ;;
esac
- exit ;;
+ ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64-unknown-linux-$LIBC
+ ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc-unknown-linux-$LIBC
+ ;;
ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpc64le-unknown-linux-$LIBC
+ ;;
ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-"$LIBC"
- exit ;;
- riscv32:Linux:*:* | riscv64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=powerpcle-unknown-linux-$LIBC
+ ;;
+ riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+ ;;
sh64*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sh*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
tile*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
vax:Linux:*:*)
- echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+ ;;
x86_64:Linux:*:*)
- echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
- exit ;;
+ set_cc_for_build
+ CPU=$UNAME_MACHINE
+ LIBCABI=$LIBC
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
+ ABI=64
+ sed 's/^ //' << EOF > "$dummy.c"
+ #ifdef __i386__
+ ABI=x86
+ #else
+ #ifdef __ILP32__
+ ABI=x32
+ #endif
+ #endif
+EOF
+ cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'`
+ eval "$cc_set_abi"
+ case $ABI in
+ x86) CPU=i686 ;;
+ x32) LIBCABI=${LIBC}x32 ;;
+ esac
+ fi
+ GUESS=$CPU-pc-linux-$LIBCABI
+ ;;
xtensa*:Linux:*:*)
- echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+ ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
# sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
+ GUESS=i386-sequent-sysv4
+ ;;
i*86:UNIX_SV:4.2MP:2.*)
# Unixware is an offshoot of SVR4, but it has its own version
# number series starting with 2...
# I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
# Use sysv4.2uw... so that sysv4* matches it.
- echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+ ;;
i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
+ # If we were able to find 'uname', then EMX Unix compatibility
# is probably installed.
- echo "$UNAME_MACHINE"-pc-os2-emx
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-os2-emx
+ ;;
i*86:XTS-300:*:STOP)
- echo "$UNAME_MACHINE"-unknown-stop
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-stop
+ ;;
i*86:atheos:*:*)
- echo "$UNAME_MACHINE"-unknown-atheos
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-atheos
+ ;;
i*86:syllable:*:*)
- echo "$UNAME_MACHINE"-pc-syllable
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-syllable
+ ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
- echo i386-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=i386-unknown-lynxos$UNAME_RELEASE
+ ;;
i*86:*DOS:*:*)
- echo "$UNAME_MACHINE"-pc-msdosdjgpp
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+ ;;
i*86:*:4.*:*)
UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
fi
- exit ;;
+ ;;
i*86:*:5:[678]*)
# UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
@@ -1141,12 +1268,12 @@ EOF
*Pentium) UNAME_MACHINE=i586 ;;
*Pent*|*Celeron) UNAME_MACHINE=i686 ;;
esac
- echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ ;;
i*86:*:3.2:*)
if test -f /usr/options/cb.name; then
UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1156,11 +1283,11 @@ EOF
&& UNAME_MACHINE=i686
(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
&& UNAME_MACHINE=i686
- echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
else
- echo "$UNAME_MACHINE"-pc-sysv32
+ GUESS=$UNAME_MACHINE-pc-sysv32
fi
- exit ;;
+ ;;
pc:*:*:*)
# Left here for compatibility:
# uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1168,31 +1295,31 @@ EOF
# Note: whatever this is, it MUST be the same as what config.sub
# prints for the "djgpp" host, or else GDB configure will decide that
# this is a cross-build.
- echo i586-pc-msdosdjgpp
- exit ;;
+ GUESS=i586-pc-msdosdjgpp
+ ;;
Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
+ GUESS=i386-pc-mach3
+ ;;
paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
+ GUESS=i860-intel-osf1
+ ;;
i860:*:4.*:*) # i860-SVR4
if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4
else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4
fi
- exit ;;
+ ;;
mini*:CTIX:SYS*5:*)
# "miniframe"
- echo m68010-convergent-sysv
- exit ;;
+ GUESS=m68010-convergent-sysv
+ ;;
mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
+ GUESS=m68k-convergent-sysv
+ ;;
M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
+ GUESS=m68k-diab-dnix
+ ;;
M68*:*:R3V[5678]*:*)
test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
@@ -1217,113 +1344,119 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
&& { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+ ;;
mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
+ GUESS=m68k-atari-sysv4
+ ;;
TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+ ;;
rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+ ;;
PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
- echo powerpc-unknown-lynxos"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+ ;;
SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-dde-sysv$UNAME_RELEASE
+ ;;
RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
+ GUESS=mips-sni-sysv4
+ ;;
*:SINIX-*:*:*)
if uname -p 2>/dev/null >/dev/null ; then
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo "$UNAME_MACHINE"-sni-sysv4
+ GUESS=$UNAME_MACHINE-sni-sysv4
else
- echo ns32k-sni-sysv
+ GUESS=ns32k-sni-sysv
fi
- exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ ;;
+ PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort
# says
- echo i586-unisys-sysv4
- exit ;;
+ GUESS=i586-unisys-sysv4
+ ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes .
# How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
+ GUESS=hppa1.1-stratus-sysv4
+ ;;
*:*:*:FTX*)
# From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit ;;
+ GUESS=i860-stratus-sysv4
+ ;;
i*86:VOS:*:*)
# From Paul.Green@stratus.com.
- echo "$UNAME_MACHINE"-stratus-vos
- exit ;;
+ GUESS=$UNAME_MACHINE-stratus-vos
+ ;;
*:VOS:*:*)
# From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit ;;
+ GUESS=hppa1.1-stratus-vos
+ ;;
mc68*:A/UX:*:*)
- echo m68k-apple-aux"$UNAME_RELEASE"
- exit ;;
+ GUESS=m68k-apple-aux$UNAME_RELEASE
+ ;;
news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
+ GUESS=mips-sony-newsos6
+ ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv"$UNAME_RELEASE"
+ if test -d /usr/nec; then
+ GUESS=mips-nec-sysv$UNAME_RELEASE
else
- echo mips-unknown-sysv"$UNAME_RELEASE"
+ GUESS=mips-unknown-sysv$UNAME_RELEASE
fi
- exit ;;
+ ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
+ GUESS=powerpc-be-beos
+ ;;
BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
+ GUESS=powerpc-apple-beos
+ ;;
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
+ GUESS=i586-pc-beos
+ ;;
BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
- echo i586-pc-haiku
- exit ;;
- x86_64:Haiku:*:*)
- echo x86_64-unknown-haiku
- exit ;;
+ GUESS=i586-pc-haiku
+ ;;
+ ppc:Haiku:*:*) # Haiku running on Apple PowerPC
+ GUESS=powerpc-apple-haiku
+ ;;
+ *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat)
+ GUESS=$UNAME_MACHINE-unknown-haiku
+ ;;
SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx4-nec-superux$UNAME_RELEASE
+ ;;
SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx5-nec-superux$UNAME_RELEASE
+ ;;
SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx6-nec-superux$UNAME_RELEASE
+ ;;
SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx7-nec-superux$UNAME_RELEASE
+ ;;
SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8-nec-superux$UNAME_RELEASE
+ ;;
SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sx8r-nec-superux$UNAME_RELEASE
+ ;;
SX-ACE:SUPER-UX:*:*)
- echo sxace-nec-superux"$UNAME_RELEASE"
- exit ;;
+ GUESS=sxace-nec-superux$UNAME_RELEASE
+ ;;
Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+ ;;
*:Rhapsody:*:*)
- echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+ ;;
+ arm64:Darwin:*:*)
+ GUESS=aarch64-apple-darwin$UNAME_RELEASE
+ ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p`
case $UNAME_PROCESSOR in
@@ -1338,7 +1471,7 @@ EOF
else
set_cc_for_build
fi
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if test "$CC_FOR_BUILD" != no_compiler_found; then
if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
grep IS_64BIT_ARCH >/dev/null
@@ -1359,109 +1492,122 @@ EOF
# uname -m returns i386 or x86_64
UNAME_PROCESSOR=$UNAME_MACHINE
fi
- echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+ ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
UNAME_PROCESSOR=`uname -p`
if test "$UNAME_PROCESSOR" = x86; then
UNAME_PROCESSOR=i386
UNAME_MACHINE=pc
fi
- echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+ ;;
*:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
+ GUESS=i386-pc-qnx
+ ;;
NEO-*:NONSTOP_KERNEL:*:*)
- echo neo-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=neo-tandem-nsk$UNAME_RELEASE
+ ;;
NSE-*:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nse-tandem-nsk$UNAME_RELEASE
+ ;;
NSR-*:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsr-tandem-nsk$UNAME_RELEASE
+ ;;
NSV-*:NONSTOP_KERNEL:*:*)
- echo nsv-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsv-tandem-nsk$UNAME_RELEASE
+ ;;
NSX-*:NONSTOP_KERNEL:*:*)
- echo nsx-tandem-nsk"$UNAME_RELEASE"
- exit ;;
+ GUESS=nsx-tandem-nsk$UNAME_RELEASE
+ ;;
*:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
+ GUESS=mips-compaq-nonstopux
+ ;;
BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
+ GUESS=bs2000-siemens-sysv
+ ;;
DS/*:UNIX_System_V:*:*)
- echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+ ;;
*:Plan9:*:*)
# "uname -m" is not consistent, so use $cputype instead. 386
# is converted to i386 for consistency with other x86
# operating systems.
- # shellcheck disable=SC2154
- if test "$cputype" = 386; then
+ if test "${cputype-}" = 386; then
UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
+ elif test "x${cputype-}" != x; then
+ UNAME_MACHINE=$cputype
fi
- echo "$UNAME_MACHINE"-unknown-plan9
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-plan9
+ ;;
*:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
+ GUESS=pdp10-unknown-tops10
+ ;;
*:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
+ GUESS=pdp10-unknown-tenex
+ ;;
KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
+ GUESS=pdp10-dec-tops20
+ ;;
XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
+ GUESS=pdp10-xkl-tops20
+ ;;
*:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
+ GUESS=pdp10-unknown-tops20
+ ;;
*:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
+ GUESS=pdp10-unknown-its
+ ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux"$UNAME_RELEASE"
- exit ;;
+ GUESS=mips-sei-seiux$UNAME_RELEASE
+ ;;
*:DragonFly:*:*)
- echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
- exit ;;
+ DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+ GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+ ;;
*:*VMS:*:*)
UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "$UNAME_MACHINE" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
+ case $UNAME_MACHINE in
+ A*) GUESS=alpha-dec-vms ;;
+ I*) GUESS=ia64-dec-vms ;;
+ V*) GUESS=vax-dec-vms ;;
esac ;;
*:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
+ GUESS=i386-pc-xenix
+ ;;
i*86:skyos:*:*)
- echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
- exit ;;
+ SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+ GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+ ;;
i*86:rdos:*:*)
- echo "$UNAME_MACHINE"-pc-rdos
- exit ;;
- i*86:AROS:*:*)
- echo "$UNAME_MACHINE"-pc-aros
- exit ;;
+ GUESS=$UNAME_MACHINE-pc-rdos
+ ;;
+ i*86:Fiwix:*:*)
+ GUESS=$UNAME_MACHINE-pc-fiwix
+ ;;
+ *:AROS:*:*)
+ GUESS=$UNAME_MACHINE-unknown-aros
+ ;;
x86_64:VMkernel:*:*)
- echo "$UNAME_MACHINE"-unknown-esx
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-esx
+ ;;
amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
- exit ;;
+ GUESS=x86_64-unknown-onefs
+ ;;
*:Unleashed:*:*)
- echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
- exit ;;
+ GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+ ;;
+ *:Ironclad:*:*)
+ GUESS=$UNAME_MACHINE-unknown-ironclad
+ ;;
esac
+# Do we have a guess based on uname results?
+if test "x$GUESS" != x; then
+ echo "$GUESS"
+ exit
+fi
+
# No uname command or uname output not recognized.
set_cc_for_build
cat > "$dummy.c" < "$dummy.c" </dev/null && SYSTEM_NAME=`$dummy` &&
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
{ echo "$SYSTEM_NAME"; exit; }
# Apollos put the system type in the environment.
@@ -1601,7 +1748,7 @@ test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
echo "$0: unable to guess system type" >&2
-case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+case $UNAME_MACHINE:$UNAME_SYSTEM in
mips:Linux | mips64:Linux)
# If we got here on MIPS GNU/Linux, output extra information.
cat >&2 <&2 <&2
+ echo "Invalid configuration '$1': more than four components" >&2
exit 1
;;
*-*-*-*)
basic_machine=$field1-$field2
- os=$field3-$field4
+ basic_os=$field3-$field4
;;
*-*-*)
# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
# parts
maybe_os=$field2-$field3
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
- | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
- | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
- | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
- | storm-chaos* | os2-emx* | rtmk-nova*)
+ cloudabi*-eabi* \
+ | kfreebsd*-gnu* \
+ | knetbsd*-gnu* \
+ | kopensolaris*-gnu* \
+ | linux-* \
+ | managarm-* \
+ | netbsd*-eabi* \
+ | netbsd*-gnu* \
+ | nto-qnx* \
+ | os2-emx* \
+ | rtmk-nova* \
+ | storm-chaos* \
+ | uclinux-gnu* \
+ | uclinux-uclibc* \
+ | windows-* )
basic_machine=$field1
- os=$maybe_os
+ basic_os=$maybe_os
;;
android-linux)
basic_machine=$field1-unknown
- os=linux-android
+ basic_os=linux-android
;;
*)
basic_machine=$field1-$field2
- os=$field3
+ basic_os=$field3
;;
esac
;;
*-*)
- # A lone config we happen to match not fitting any pattern
case $field1-$field2 in
+ # Shorthands that happen to contain a single dash
+ convex-c[12] | convex-c3[248])
+ basic_machine=$field2-convex
+ basic_os=
+ ;;
decstation-3100)
basic_machine=mips-dec
- os=
+ basic_os=
;;
*-*)
# Second component is usually, but not always the OS
case $field2 in
- # Prevent following clause from handling this valid os
+ # Do not treat sunos as a manufacturer
sun*os*)
basic_machine=$field1
- os=$field2
+ basic_os=$field2
;;
# Manufacturers
- dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
- | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
- | unicom* | ibm* | next | hp | isi* | apollo | altos* \
- | convergent* | ncr* | news | 32* | 3600* | 3100* \
- | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
- | ultra | tti* | harris | dolphin | highlevel | gould \
- | cbm | ns | masscomp | apple | axis | knuth | cray \
- | microblaze* | sim | cisco \
- | oki | wec | wrs | winbond)
+ 3100* \
+ | 32* \
+ | 3300* \
+ | 3600* \
+ | 7300* \
+ | acorn \
+ | altos* \
+ | apollo \
+ | apple \
+ | atari \
+ | att* \
+ | axis \
+ | be \
+ | bull \
+ | cbm \
+ | ccur \
+ | cisco \
+ | commodore \
+ | convergent* \
+ | convex* \
+ | cray \
+ | crds \
+ | dec* \
+ | delta* \
+ | dg \
+ | digital \
+ | dolphin \
+ | encore* \
+ | gould \
+ | harris \
+ | highlevel \
+ | hitachi* \
+ | hp \
+ | ibm* \
+ | intergraph \
+ | isi* \
+ | knuth \
+ | masscomp \
+ | microblaze* \
+ | mips* \
+ | motorola* \
+ | ncr* \
+ | news \
+ | next \
+ | ns \
+ | oki \
+ | omron* \
+ | pc533* \
+ | rebel \
+ | rom68k \
+ | rombug \
+ | semi \
+ | sequent* \
+ | siemens \
+ | sgi* \
+ | siemens \
+ | sim \
+ | sni \
+ | sony* \
+ | stratus \
+ | sun \
+ | sun[234]* \
+ | tektronix \
+ | tti* \
+ | ultra \
+ | unicom* \
+ | wec \
+ | winbond \
+ | wrs)
basic_machine=$field1-$field2
- os=
+ basic_os=
+ ;;
+ zephyr*)
+ basic_machine=$field1-unknown
+ basic_os=$field2
;;
*)
basic_machine=$field1
- os=$field2
+ basic_os=$field2
;;
esac
;;
@@ -191,450 +279,431 @@ case $1 in
case $field1 in
386bsd)
basic_machine=i386-pc
- os=bsd
+ basic_os=bsd
;;
a29khif)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
adobe68k)
basic_machine=m68010-adobe
- os=scout
+ basic_os=scout
;;
alliant)
basic_machine=fx80-alliant
- os=
+ basic_os=
;;
altos | altos3068)
basic_machine=m68k-altos
- os=
+ basic_os=
;;
am29k)
basic_machine=a29k-none
- os=bsd
+ basic_os=bsd
;;
amdahl)
basic_machine=580-amdahl
- os=sysv
+ basic_os=sysv
;;
amiga)
basic_machine=m68k-unknown
- os=
+ basic_os=
;;
amigaos | amigados)
basic_machine=m68k-unknown
- os=amigaos
+ basic_os=amigaos
;;
amigaunix | amix)
basic_machine=m68k-unknown
- os=sysv4
+ basic_os=sysv4
;;
apollo68)
basic_machine=m68k-apollo
- os=sysv
+ basic_os=sysv
;;
apollo68bsd)
basic_machine=m68k-apollo
- os=bsd
+ basic_os=bsd
;;
aros)
basic_machine=i386-pc
- os=aros
+ basic_os=aros
;;
aux)
basic_machine=m68k-apple
- os=aux
+ basic_os=aux
;;
balance)
basic_machine=ns32k-sequent
- os=dynix
+ basic_os=dynix
;;
blackfin)
basic_machine=bfin-unknown
- os=linux
+ basic_os=linux
;;
cegcc)
basic_machine=arm-unknown
- os=cegcc
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=bsd
+ basic_os=cegcc
;;
cray)
basic_machine=j90-cray
- os=unicos
+ basic_os=unicos
;;
crds | unos)
basic_machine=m68k-crds
- os=
+ basic_os=
;;
da30)
basic_machine=m68k-da30
- os=
+ basic_os=
;;
decstation | pmax | pmin | dec3100 | decstatn)
basic_machine=mips-dec
- os=
+ basic_os=
;;
delta88)
basic_machine=m88k-motorola
- os=sysv3
+ basic_os=sysv3
;;
dicos)
basic_machine=i686-pc
- os=dicos
+ basic_os=dicos
;;
djgpp)
basic_machine=i586-pc
- os=msdosdjgpp
+ basic_os=msdosdjgpp
;;
ebmon29k)
basic_machine=a29k-amd
- os=ebmon
+ basic_os=ebmon
;;
es1800 | OSE68k | ose68k | ose | OSE)
basic_machine=m68k-ericsson
- os=ose
+ basic_os=ose
;;
gmicro)
basic_machine=tron-gmicro
- os=sysv
+ basic_os=sysv
;;
go32)
basic_machine=i386-pc
- os=go32
+ basic_os=go32
;;
h8300hms)
basic_machine=h8300-hitachi
- os=hms
+ basic_os=hms
;;
h8300xray)
basic_machine=h8300-hitachi
- os=xray
+ basic_os=xray
;;
h8500hms)
basic_machine=h8500-hitachi
- os=hms
+ basic_os=hms
;;
harris)
basic_machine=m88k-harris
- os=sysv3
+ basic_os=sysv3
;;
- hp300)
+ hp300 | hp300hpux)
basic_machine=m68k-hp
+ basic_os=hpux
;;
hp300bsd)
basic_machine=m68k-hp
- os=bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=hpux
+ basic_os=bsd
;;
hppaosf)
basic_machine=hppa1.1-hp
- os=osf
+ basic_os=osf
;;
hppro)
basic_machine=hppa1.1-hp
- os=proelf
+ basic_os=proelf
;;
i386mach)
basic_machine=i386-mach
- os=mach
- ;;
- vsta)
- basic_machine=i386-pc
- os=vsta
+ basic_os=mach
;;
isi68 | isi)
basic_machine=m68k-isi
- os=sysv
+ basic_os=sysv
;;
m68knommu)
basic_machine=m68k-unknown
- os=linux
+ basic_os=linux
;;
magnum | m3230)
basic_machine=mips-mips
- os=sysv
+ basic_os=sysv
;;
merlin)
basic_machine=ns32k-utek
- os=sysv
+ basic_os=sysv
;;
mingw64)
basic_machine=x86_64-pc
- os=mingw64
+ basic_os=mingw64
;;
mingw32)
basic_machine=i686-pc
- os=mingw32
+ basic_os=mingw32
;;
mingw32ce)
basic_machine=arm-unknown
- os=mingw32ce
+ basic_os=mingw32ce
;;
monitor)
basic_machine=m68k-rom68k
- os=coff
+ basic_os=coff
;;
morphos)
basic_machine=powerpc-unknown
- os=morphos
+ basic_os=morphos
;;
moxiebox)
basic_machine=moxie-unknown
- os=moxiebox
+ basic_os=moxiebox
;;
msdos)
basic_machine=i386-pc
- os=msdos
+ basic_os=msdos
;;
msys)
basic_machine=i686-pc
- os=msys
+ basic_os=msys
;;
mvs)
basic_machine=i370-ibm
- os=mvs
+ basic_os=mvs
;;
nacl)
basic_machine=le32-unknown
- os=nacl
+ basic_os=nacl
;;
ncr3000)
basic_machine=i486-ncr
- os=sysv4
+ basic_os=sysv4
;;
netbsd386)
basic_machine=i386-pc
- os=netbsd
+ basic_os=netbsd
;;
netwinder)
basic_machine=armv4l-rebel
- os=linux
+ basic_os=linux
;;
news | news700 | news800 | news900)
basic_machine=m68k-sony
- os=newsos
+ basic_os=newsos
;;
news1000)
basic_machine=m68030-sony
- os=newsos
+ basic_os=newsos
;;
necv70)
basic_machine=v70-nec
- os=sysv
+ basic_os=sysv
;;
nh3000)
basic_machine=m68k-harris
- os=cxux
+ basic_os=cxux
;;
nh[45]000)
basic_machine=m88k-harris
- os=cxux
+ basic_os=cxux
;;
nindy960)
basic_machine=i960-intel
- os=nindy
+ basic_os=nindy
;;
mon960)
basic_machine=i960-intel
- os=mon960
+ basic_os=mon960
;;
nonstopux)
basic_machine=mips-compaq
- os=nonstopux
+ basic_os=nonstopux
;;
os400)
basic_machine=powerpc-ibm
- os=os400
+ basic_os=os400
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
- os=ose
+ basic_os=ose
;;
os68k)
basic_machine=m68k-none
- os=os68k
+ basic_os=os68k
;;
paragon)
basic_machine=i860-intel
- os=osf
+ basic_os=osf
;;
parisc)
basic_machine=hppa-unknown
- os=linux
+ basic_os=linux
+ ;;
+ psp)
+ basic_machine=mipsallegrexel-sony
+ basic_os=psp
;;
pw32)
basic_machine=i586-unknown
- os=pw32
+ basic_os=pw32
;;
rdos | rdos64)
basic_machine=x86_64-pc
- os=rdos
+ basic_os=rdos
;;
rdos32)
basic_machine=i386-pc
- os=rdos
+ basic_os=rdos
;;
rom68k)
basic_machine=m68k-rom68k
- os=coff
+ basic_os=coff
;;
sa29200)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
sei)
basic_machine=mips-sei
- os=seiux
+ basic_os=seiux
;;
sequent)
basic_machine=i386-sequent
- os=
+ basic_os=
;;
sps7)
basic_machine=m68k-bull
- os=sysv2
+ basic_os=sysv2
;;
st2000)
basic_machine=m68k-tandem
- os=
+ basic_os=
;;
stratus)
basic_machine=i860-stratus
- os=sysv4
+ basic_os=sysv4
;;
sun2)
basic_machine=m68000-sun
- os=
+ basic_os=
;;
sun2os3)
basic_machine=m68000-sun
- os=sunos3
+ basic_os=sunos3
;;
sun2os4)
basic_machine=m68000-sun
- os=sunos4
+ basic_os=sunos4
;;
sun3)
basic_machine=m68k-sun
- os=
+ basic_os=
;;
sun3os3)
basic_machine=m68k-sun
- os=sunos3
+ basic_os=sunos3
;;
sun3os4)
basic_machine=m68k-sun
- os=sunos4
+ basic_os=sunos4
;;
sun4)
basic_machine=sparc-sun
- os=
+ basic_os=
;;
sun4os3)
basic_machine=sparc-sun
- os=sunos3
+ basic_os=sunos3
;;
sun4os4)
basic_machine=sparc-sun
- os=sunos4
+ basic_os=sunos4
;;
sun4sol2)
basic_machine=sparc-sun
- os=solaris2
+ basic_os=solaris2
;;
sun386 | sun386i | roadrunner)
basic_machine=i386-sun
- os=
+ basic_os=
;;
sv1)
basic_machine=sv1-cray
- os=unicos
+ basic_os=unicos
;;
symmetry)
basic_machine=i386-sequent
- os=dynix
+ basic_os=dynix
;;
t3e)
basic_machine=alphaev5-cray
- os=unicos
+ basic_os=unicos
;;
t90)
basic_machine=t90-cray
- os=unicos
+ basic_os=unicos
;;
toad1)
basic_machine=pdp10-xkl
- os=tops20
+ basic_os=tops20
;;
tpf)
basic_machine=s390x-ibm
- os=tpf
+ basic_os=tpf
;;
udi29k)
basic_machine=a29k-amd
- os=udi
+ basic_os=udi
;;
ultra3)
basic_machine=a29k-nyu
- os=sym1
+ basic_os=sym1
;;
v810 | necv810)
basic_machine=v810-nec
- os=none
+ basic_os=none
;;
vaxv)
basic_machine=vax-dec
- os=sysv
+ basic_os=sysv
;;
vms)
basic_machine=vax-dec
- os=vms
+ basic_os=vms
+ ;;
+ vsta)
+ basic_machine=i386-pc
+ basic_os=vsta
;;
vxworks960)
basic_machine=i960-wrs
- os=vxworks
+ basic_os=vxworks
;;
vxworks68)
basic_machine=m68k-wrs
- os=vxworks
+ basic_os=vxworks
;;
vxworks29k)
basic_machine=a29k-wrs
- os=vxworks
+ basic_os=vxworks
;;
xbox)
basic_machine=i686-pc
- os=mingw32
+ basic_os=mingw32
;;
ymp)
basic_machine=ymp-cray
- os=unicos
+ basic_os=unicos
;;
*)
basic_machine=$1
- os=
+ basic_os=
;;
esac
;;
@@ -686,27 +755,38 @@ case $basic_machine in
bluegene*)
cpu=powerpc
vendor=ibm
- os=cnk
+ basic_os=cnk
;;
decsystem10* | dec10*)
cpu=pdp10
vendor=dec
- os=tops10
+ basic_os=tops10
;;
decsystem20* | dec20*)
cpu=pdp10
vendor=dec
- os=tops20
+ basic_os=tops20
;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
+ delta | 3300 | delta-motorola | 3300-motorola | motorola-delta | motorola-3300)
cpu=m68k
vendor=motorola
;;
- dpx2*)
+ # This used to be dpx2*, but that gets the RS6000-based
+ # DPX/20 and the x86-based DPX/2-100 wrong. See
+ # https://oldskool.silicium.org/stations/bull_dpx20.htm
+ # https://www.feb-patrimoine.com/english/bull_dpx2.htm
+ # https://www.feb-patrimoine.com/english/unix_and_bull.htm
+ dpx2 | dpx2[23]00 | dpx2[23]xx)
cpu=m68k
vendor=bull
- os=sysv3
+ ;;
+ dpx2100 | dpx21xx)
+ cpu=i386
+ vendor=bull
+ ;;
+ dpx20)
+ cpu=rs6000
+ vendor=bull
;;
encore | umax | mmax)
cpu=ns32k
@@ -715,7 +795,7 @@ case $basic_machine in
elxsi)
cpu=elxsi
vendor=elxsi
- os=${os:-bsd}
+ basic_os=${basic_os:-bsd}
;;
fx2800)
cpu=i860
@@ -728,7 +808,7 @@ case $basic_machine in
h3050r* | hiux*)
cpu=hppa1.1
vendor=hitachi
- os=hiuxwe2
+ basic_os=hiuxwe2
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
cpu=hppa1.0
@@ -771,36 +851,36 @@ case $basic_machine in
i*86v32)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
- os=sysv32
+ basic_os=sysv32
;;
i*86v4*)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
- os=sysv4
+ basic_os=sysv4
;;
i*86v)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
- os=sysv
+ basic_os=sysv
;;
i*86sol2)
cpu=`echo "$1" | sed -e 's/86.*/86/'`
vendor=pc
- os=solaris2
+ basic_os=solaris2
;;
j90 | j90-cray)
cpu=j90
vendor=cray
- os=${os:-unicos}
+ basic_os=${basic_os:-unicos}
;;
iris | iris4d)
cpu=mips
vendor=sgi
- case $os in
+ case $basic_os in
irix*)
;;
*)
- os=irix4
+ basic_os=irix4
;;
esac
;;
@@ -811,28 +891,16 @@ case $basic_machine in
*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
cpu=m68k
vendor=atari
- os=mint
+ basic_os=mint
;;
news-3600 | risc-news)
cpu=mips
vendor=sony
- os=newsos
+ basic_os=newsos
;;
next | m*-next)
cpu=m68k
vendor=next
- case $os in
- openstep*)
- ;;
- nextstep*)
- ;;
- ns2*)
- os=nextstep2
- ;;
- *)
- os=nextstep3
- ;;
- esac
;;
np1)
cpu=np1
@@ -841,12 +909,12 @@ case $basic_machine in
op50n-* | op60c-*)
cpu=hppa1.1
vendor=oki
- os=proelf
+ basic_os=proelf
;;
pa-hitachi)
cpu=hppa1.1
vendor=hitachi
- os=hiuxwe2
+ basic_os=hiuxwe2
;;
pbd)
cpu=sparc
@@ -883,12 +951,12 @@ case $basic_machine in
sde)
cpu=mipsisa32
vendor=sde
- os=${os:-elf}
+ basic_os=${basic_os:-elf}
;;
simso-wrs)
cpu=sparclite
vendor=wrs
- os=vxworks
+ basic_os=vxworks
;;
tower | tower-32)
cpu=m68k
@@ -905,7 +973,7 @@ case $basic_machine in
w89k-*)
cpu=hppa1.1
vendor=winbond
- os=proelf
+ basic_os=proelf
;;
none)
cpu=none
@@ -921,12 +989,13 @@ case $basic_machine in
;;
*-*)
- # shellcheck disable=SC2162
+ saved_IFS=$IFS
IFS="-" read cpu vendor <&2
+ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
exit 1
;;
esac
@@ -1278,8 +1491,53 @@ esac
# Decode manufacturer-specific aliases for certain operating systems.
-if [ x$os != x ]
+if test x"$basic_os" != x
then
+
+# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
+# set os.
+obj=
+case $basic_os in
+ gnu/linux*)
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
+ ;;
+ os2-emx)
+ kernel=os2
+ os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
+ ;;
+ nto-qnx*)
+ kernel=nto
+ os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
+ ;;
+ *-*)
+ saved_IFS=$IFS
+ IFS="-" read kernel os <&2
- exit 1
+ # No normalization, but not necessarily accepted, that comes below.
;;
esac
+
else
# Here we handle the default operating systems that come with various machines.
@@ -1533,42 +1744,54 @@ else
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.
+kernel=
+obj=
case $cpu-$vendor in
score-*)
- os=elf
+ os=
+ obj=elf
;;
spu-*)
- os=elf
+ os=
+ obj=elf
;;
*-acorn)
os=riscix1.2
;;
arm*-rebel)
- os=linux
+ kernel=linux
+ os=gnu
;;
arm*-semi)
- os=aout
+ os=
+ obj=aout
;;
c4x-* | tic4x-*)
- os=coff
+ os=
+ obj=coff
;;
c8051-*)
- os=elf
+ os=
+ obj=elf
;;
clipper-intergraph)
os=clix
;;
hexagon-*)
- os=elf
+ os=
+ obj=elf
;;
tic54x-*)
- os=coff
+ os=
+ obj=coff
;;
tic55x-*)
- os=coff
+ os=
+ obj=coff
;;
tic6x-*)
- os=coff
+ os=
+ obj=coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1590,28 +1813,43 @@ case $cpu-$vendor in
os=sunos3
;;
m68*-cisco)
- os=aout
+ os=
+ obj=aout
;;
mep-*)
- os=elf
+ os=
+ obj=elf
+ ;;
+ # The -sgi and -siemens entries must be before the mips- entry
+ # or we get the wrong os.
+ *-sgi)
+ os=irix
+ ;;
+ *-siemens)
+ os=sysv4
;;
mips*-cisco)
- os=elf
+ os=
+ obj=elf
;;
- mips*-*)
- os=elf
+ mips*-*|nanomips*-*)
+ os=
+ obj=elf
;;
or32-*)
- os=coff
+ os=
+ obj=coff
;;
- *-tti) # must be before sparc entry or we get the wrong os.
+ # This must be before the sparc-* entry or we get the wrong os.
+ *-tti)
os=sysv3
;;
sparc-* | *-sun)
os=sunos4.1.1
;;
pru-*)
- os=elf
+ os=
+ obj=elf
;;
*-be)
os=beos
@@ -1635,7 +1873,7 @@ case $cpu-$vendor in
os=hpux
;;
*-hitachi)
- os=hiux
+ os=hiuxwe2
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
os=sysv
@@ -1679,12 +1917,6 @@ case $cpu-$vendor in
*-encore)
os=bsd
;;
- *-sgi)
- os=irix
- ;;
- *-siemens)
- os=sysv4
- ;;
*-masscomp)
os=rtu
;;
@@ -1692,10 +1924,12 @@ case $cpu-$vendor in
os=uxpv
;;
*-rom68k)
- os=coff
+ os=
+ obj=coff
;;
*-*bug)
- os=coff
+ os=
+ obj=coff
;;
*-apple)
os=macos
@@ -1710,84 +1944,406 @@ case $cpu-$vendor in
os=none
;;
esac
+
fi
+# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
+
+case $os in
+ # Sometimes we do "kernel-libc", so those need to count as OSes.
+ llvm* | musl* | newlib* | relibc* | uclibc*)
+ ;;
+ # Likewise for "kernel-abi"
+ eabi* | gnueabi*)
+ ;;
+ # VxWorks passes extra cpu info in the 4th filed.
+ simlinux | simwindows | spe)
+ ;;
+ # See `case $cpu-$os` validation below
+ ghcjs)
+ ;;
+ # Now accept the basic system types.
+ # Each alternative MUST end in a * to match a version number.
+ abug \
+ | aix* \
+ | amdhsa* \
+ | amigados* \
+ | amigaos* \
+ | android* \
+ | aof* \
+ | aos* \
+ | aros* \
+ | atheos* \
+ | auroraux* \
+ | aux* \
+ | beos* \
+ | bitrig* \
+ | bme* \
+ | bosx* \
+ | bsd* \
+ | cegcc* \
+ | chorusos* \
+ | chorusrdb* \
+ | clix* \
+ | cloudabi* \
+ | cnk* \
+ | conix* \
+ | cos* \
+ | cxux* \
+ | cygwin* \
+ | darwin* \
+ | dgux* \
+ | dicos* \
+ | dnix* \
+ | domain* \
+ | dragonfly* \
+ | drops* \
+ | ebmon* \
+ | ecoff* \
+ | ekkobsd* \
+ | emscripten* \
+ | emx* \
+ | es* \
+ | fiwix* \
+ | freebsd* \
+ | fuchsia* \
+ | genix* \
+ | genode* \
+ | glidix* \
+ | gnu* \
+ | go32* \
+ | haiku* \
+ | hcos* \
+ | hiux* \
+ | hms* \
+ | hpux* \
+ | ieee* \
+ | interix* \
+ | ios* \
+ | iris* \
+ | irix* \
+ | ironclad* \
+ | isc* \
+ | its* \
+ | l4re* \
+ | libertybsd* \
+ | lites* \
+ | lnews* \
+ | luna* \
+ | lynxos* \
+ | mach* \
+ | macos* \
+ | magic* \
+ | mbr* \
+ | midipix* \
+ | midnightbsd* \
+ | mingw32* \
+ | mingw64* \
+ | minix* \
+ | mint* \
+ | mirbsd* \
+ | mks* \
+ | mlibc* \
+ | mmixware* \
+ | mon960* \
+ | morphos* \
+ | moss* \
+ | moxiebox* \
+ | mpeix* \
+ | mpw* \
+ | msdos* \
+ | msys* \
+ | mvs* \
+ | nacl* \
+ | netbsd* \
+ | netware* \
+ | newsos* \
+ | nextstep* \
+ | nindy* \
+ | nonstopux* \
+ | nova* \
+ | nsk* \
+ | nucleus* \
+ | nx6 \
+ | nx7 \
+ | oabi* \
+ | ohos* \
+ | onefs* \
+ | openbsd* \
+ | openedition* \
+ | openstep* \
+ | os108* \
+ | os2* \
+ | os400* \
+ | os68k* \
+ | os9* \
+ | ose* \
+ | osf* \
+ | oskit* \
+ | osx* \
+ | palmos* \
+ | phoenix* \
+ | plan9* \
+ | powermax* \
+ | powerunix* \
+ | proelf* \
+ | psos* \
+ | psp* \
+ | ptx* \
+ | pw32* \
+ | qnx* \
+ | rdos* \
+ | redox* \
+ | rhapsody* \
+ | riscix* \
+ | riscos* \
+ | rtems* \
+ | rtmk* \
+ | rtu* \
+ | scout* \
+ | secbsd* \
+ | sei* \
+ | serenity* \
+ | sim* \
+ | skyos* \
+ | solaris* \
+ | solidbsd* \
+ | sortix* \
+ | storm-chaos* \
+ | sunos \
+ | sunos[34]* \
+ | superux* \
+ | syllable* \
+ | sym* \
+ | sysv* \
+ | tenex* \
+ | tirtos* \
+ | toppers* \
+ | tops10* \
+ | tops20* \
+ | tpf* \
+ | tvos* \
+ | twizzler* \
+ | uclinux* \
+ | udi* \
+ | udk* \
+ | ultrix* \
+ | unicos* \
+ | uniplus* \
+ | unleashed* \
+ | unos* \
+ | uwin* \
+ | uxpv* \
+ | v88r* \
+ |*vms* \
+ | vos* \
+ | vsta* \
+ | vxsim* \
+ | vxworks* \
+ | wasi* \
+ | watchos* \
+ | wince* \
+ | windiss* \
+ | windows* \
+ | winnt* \
+ | xenix* \
+ | xray* \
+ | zephyr* \
+ | zvmoe* )
+ ;;
+ # This one is extra strict with allowed versions
+ sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
+ # This refers to builds using the UEFI calling convention
+ # (which depends on the architecture) and PE file format.
+ # Note that this is both a different calling convention and
+ # different file format than that of GNU-EFI
+ # (x86_64-w64-mingw32).
+ uefi)
+ ;;
+ none)
+ ;;
+ kernel* | msvc* )
+ # Restricted further below
+ ;;
+ '')
+ if test x"$obj" = x
+ then
+ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
+ fi
+ ;;
+ *)
+ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+case $obj in
+ aout* | coff* | elf* | pe*)
+ ;;
+ '')
+ # empty is fine
+ ;;
+ *)
+ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we handle the constraint that a (synthetic) cpu and os are
+# valid only in combination with each other and nowhere else.
+case $cpu-$os in
+ # The "javascript-unknown-ghcjs" triple is used by GHC; we
+ # accept it here in order to tolerate that, but reject any
+ # variations.
+ javascript-ghcjs)
+ ;;
+ javascript-* | *-ghcjs)
+ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
+ exit 1
+ ;;
+esac
+
+# As a final step for OS-related things, validate the OS-kernel combination
+# (given a valid OS), if there is a kernel.
+case $kernel-$os-$obj in
+ linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
+ | linux-mlibc*- | linux-musl*- | linux-newlib*- \
+ | linux-relibc*- | linux-uclibc*- | linux-ohos*- )
+ ;;
+ uclinux-uclibc*- | uclinux-gnu*- )
+ ;;
+ managarm-mlibc*- | managarm-kernel*- )
+ ;;
+ windows*-msvc*-)
+ ;;
+ -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
+ | -uclibc*- )
+ # These are just libc implementations, not actual OSes, and thus
+ # require a kernel.
+ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ -kernel*- )
+ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+ *-kernel*- )
+ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
+ exit 1
+ ;;
+ *-msvc*- )
+ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
+ exit 1
+ ;;
+ kfreebsd*-gnu*- | knetbsd*-gnu*- | netbsd*-gnu*- | kopensolaris*-gnu*-)
+ ;;
+ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+ ;;
+ nto-qnx*-)
+ ;;
+ os2-emx-)
+ ;;
+ rtmk-nova-)
+ ;;
+ *-eabi*- | *-gnueabi*-)
+ ;;
+ none--*)
+ # None (no kernel, i.e. freestanding / bare metal),
+ # can be paired with an machine code file format
+ ;;
+ -*-)
+ # Blank kernel with real OS is always fine.
+ ;;
+ --*)
+ # Blank kernel and OS with real machine code file format is always fine.
+ ;;
+ *-*-*)
+ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
+ exit 1
+ ;;
+esac
+
# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer. We pick the logical manufacturer.
case $vendor in
unknown)
- case $os in
- riscix*)
+ case $cpu-$os in
+ *-riscix*)
vendor=acorn
;;
- sunos*)
+ *-sunos* | *-solaris*)
vendor=sun
;;
- cnk*|-aix*)
+ *-cnk* | *-aix*)
vendor=ibm
;;
- beos*)
+ *-beos*)
vendor=be
;;
- hpux*)
+ *-hpux*)
vendor=hp
;;
- mpeix*)
+ *-mpeix*)
vendor=hp
;;
- hiux*)
+ *-hiux*)
vendor=hitachi
;;
- unos*)
+ *-unos*)
vendor=crds
;;
- dgux*)
+ *-dgux*)
vendor=dg
;;
- luna*)
+ *-luna*)
vendor=omron
;;
- genix*)
+ *-genix*)
vendor=ns
;;
- clix*)
+ *-clix*)
vendor=intergraph
;;
- mvs* | opened*)
+ *-mvs* | *-opened*)
+ vendor=ibm
+ ;;
+ *-os400*)
vendor=ibm
;;
- os400*)
+ s390-* | s390x-*)
vendor=ibm
;;
- ptx*)
+ *-ptx*)
vendor=sequent
;;
- tpf*)
+ *-tpf*)
vendor=ibm
;;
- vxsim* | vxworks* | windiss*)
+ *-vxsim* | *-vxworks* | *-windiss*)
vendor=wrs
;;
- aux*)
+ *-aux*)
vendor=apple
;;
- hms*)
+ *-hms*)
vendor=hitachi
;;
- mpw* | macos*)
+ *-mpw* | *-macos*)
vendor=apple
;;
- *mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+ *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
vendor=atari
;;
- vos*)
+ *-vos*)
vendor=stratus
;;
esac
;;
esac
-echo "$cpu-$vendor-$os"
+echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
exit
# Local variables:
diff --git a/autosetup/autosetup-find-tclsh b/autosetup/autosetup-find-tclsh
new file mode 100755
index 0000000000..9f6d6e9402
--- /dev/null
+++ b/autosetup/autosetup-find-tclsh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Looks for a suitable tclsh or jimsh in the PATH
+# If not found, builds a bootstrap jimsh in current dir from source
+# Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
+# If an argument is given, use that as the test instead of autosetup-test-tclsh
+d="`dirname "$0"`"
+for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
+ { $tclsh "$d/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
+done
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
+for cc in ${CC_FOR_BUILD:-cc} gcc; do
+ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>/dev/null >/dev/null || continue
+ ./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
+done
+echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
+echo false
diff --git a/autosetup/autosetup-test-tclsh b/autosetup/autosetup-test-tclsh
new file mode 100644
index 0000000000..75126d2444
--- /dev/null
+++ b/autosetup/autosetup-test-tclsh
@@ -0,0 +1,20 @@
+# A small Tcl script to verify that the chosen
+# interpreter works. Sometimes we might e.g. pick up
+# an interpreter for a different arch.
+# Outputs the full path to the interpreter
+
+if {[catch {info version} version] == 0} {
+ # This is Jim Tcl
+ if {$version >= 0.72} {
+ # Ensure that regexp works
+ regexp (a.*?) a
+ puts [info nameofexecutable]
+ exit 0
+ }
+} elseif {[catch {info tclversion} version] == 0} {
+ if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
+ puts [info nameofexecutable]
+ exit 0
+ }
+}
+exit 1
diff --git a/autosetup/cc-db.tcl b/autosetup/cc-db.tcl
new file mode 100644
index 0000000000..12f1aed2c9
--- /dev/null
+++ b/autosetup/cc-db.tcl
@@ -0,0 +1,15 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-db' module provides a knowledge-base of system idiosyncrasies.
+# In general, this module can always be included.
+
+use cc
+
+options {}
+
+# openbsd needs sys/types.h to detect some system headers
+cc-include-needs sys/socket.h sys/types.h
+cc-include-needs netinet/in.h sys/types.h
diff --git a/autosetup/cc-lib.tcl b/autosetup/cc-lib.tcl
new file mode 100644
index 0000000000..01a0fb3877
--- /dev/null
+++ b/autosetup/cc-lib.tcl
@@ -0,0 +1,187 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# Provides a library of common tests on top of the 'cc' module.
+
+use cc
+
+# @cc-check-lfs
+#
+# The equivalent of the 'AC_SYS_LARGEFILE' macro.
+#
+# defines 'HAVE_LFS' if LFS is available,
+# and defines '_FILE_OFFSET_BITS=64' if necessary
+#
+# Returns 1 if 'LFS' is available or 0 otherwise
+#
+proc cc-check-lfs {} {
+ cc-check-includes sys/types.h
+ msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
+ set lfs 1
+ if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
+ msg-result no
+ } elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
+ define _FILE_OFFSET_BITS 64
+ msg-result yes
+ } else {
+ set lfs 0
+ msg-result none
+ }
+ define-feature lfs $lfs
+ return $lfs
+}
+
+# @cc-check-endian
+#
+# The equivalent of the 'AC_C_BIGENDIAN' macro.
+#
+# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
+# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
+#
+# Returns 1 if determined, or 0 if not.
+#
+proc cc-check-endian {} {
+ cc-check-includes sys/types.h sys/param.h
+ set rc 0
+ msg-checking "Checking endian..."
+ cc-with {-includes {sys/types.h sys/param.h}} {
+ if {[cctest -code {
+ #if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != BIG_ENDIAN
+ #error little
+ #endif
+ }]} {
+ define-feature big-endian
+ msg-result "big"
+ set rc 1
+ } elseif {[cctest -code {
+ #if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != LITTLE_ENDIAN
+ #error big
+ #endif
+ }]} {
+ define-feature little-endian
+ msg-result "little"
+ set rc 1
+ } else {
+ msg-result "unknown"
+ }
+ }
+ return $rc
+}
+
+# @cc-check-flags flag ?...?
+#
+# Checks whether the given C/C++ compiler flags can be used. Defines feature
+# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
+# appends working flags to '-cflags' and 'AS_CFLAGS' or 'AS_CXXFLAGS'.
+proc cc-check-flags {args} {
+ set result 1
+ array set opts [cc-get-settings]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ set lang C++
+ set prefix CXXFLAG
+ }
+ c {
+ set lang C
+ set prefix CFLAG
+ }
+ default {
+ autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
+ }
+ }
+ foreach flag $args {
+ msg-checking "Checking whether the $lang compiler accepts $flag..."
+ if {[cctest -cflags $flag]} {
+ msg-result yes
+ define-feature $prefix$flag
+ cc-with [list -cflags [list $flag]]
+ define-append AS_${prefix}S $flag
+ } else {
+ msg-result no
+ set result 0
+ }
+ }
+ return $result
+}
+
+# @cc-check-standards ver ?...?
+#
+# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
+# options, and appends the first working one to '-cflags' and 'AS_CFLAGS' or
+# 'AS_CXXFLAGS'.
+proc cc-check-standards {args} {
+ array set opts [cc-get-settings]
+ foreach std $args {
+ if {[cc-check-flags -std=$std]} {
+ return $std
+ }
+ }
+ return ""
+}
+
+# Checks whether $keyword is usable as alignof
+proc cctest_alignof {keyword} {
+ msg-checking "Checking for $keyword..."
+ if {[cctest -code "int x = ${keyword}(char), y = ${keyword}('x');"]} then {
+ msg-result ok
+ define-feature $keyword
+ } else {
+ msg-result "not found"
+ }
+}
+
+# @cc-check-c11
+#
+# Checks for several C11/C++11 extensions and their alternatives. Currently
+# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
+proc cc-check-c11 {} {
+ msg-checking "Checking for _Static_assert..."
+ if {[cctest -code {
+ _Static_assert(1, "static assertions are available");
+ }]} then {
+ msg-result ok
+ define-feature _Static_assert
+ } else {
+ msg-result "not found"
+ }
+
+ cctest_alignof _Alignof
+ cctest_alignof __alignof__
+ cctest_alignof __alignof
+}
+
+# @cc-check-alloca
+#
+# The equivalent of the 'AC_FUNC_ALLOCA' macro.
+#
+# Checks for the existence of 'alloca'
+# defines 'HAVE_ALLOCA' and returns 1 if it exists.
+proc cc-check-alloca {} {
+ cc-check-some-feature alloca {
+ cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
+ }
+}
+
+# @cc-signal-return-type
+#
+# The equivalent of the 'AC_TYPE_SIGNAL' macro.
+#
+# defines 'RETSIGTYPE' to 'int' or 'void'.
+proc cc-signal-return-type {} {
+ msg-checking "Checking return type of signal handlers..."
+ cc-with {-includes {sys/types.h signal.h}} {
+ if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
+ set type int
+ } else {
+ set type void
+ }
+ define RETSIGTYPE $type
+ msg-result $type
+ }
+}
diff --git a/autosetup/cc-shared.tcl b/autosetup/cc-shared.tcl
new file mode 100644
index 0000000000..cbe568018e
--- /dev/null
+++ b/autosetup/cc-shared.tcl
@@ -0,0 +1,113 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-shared' module provides support for shared libraries and shared objects.
+# It defines the following variables:
+#
+## SH_CFLAGS Flags to use compiling sources destined for a shared library
+## SH_LDFLAGS Flags to use linking (creating) a shared library
+## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
+## SH_SOFULLPATH Set to 1 if the shared library soname should include the full install path
+## SH_SOEXT Extension for shared libs
+## SH_SOEXTVER Format for versioned shared libs - %s = version
+## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
+## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
+## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
+## SH_LINKRPATH Format for setting the rpath when linking an executable, %s = path
+## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
+## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
+## STRIPLIBFLAGS Arguments to strip a dynamic library
+
+options {}
+
+# Defaults: gcc on unix
+define SHOBJ_CFLAGS -fPIC
+define SHOBJ_LDFLAGS -shared
+define SH_CFLAGS -fPIC
+define SH_LDFLAGS -shared
+define SH_LINKFLAGS -rdynamic
+define SH_LINKRPATH "-Wl,-rpath -Wl,%s"
+define SH_SOEXT .so
+define SH_SOEXTVER .so.%s
+define SH_SOPREFIX -Wl,-soname,
+define LD_LIBRARY_PATH LD_LIBRARY_PATH
+define STRIPLIBFLAGS --strip-unneeded
+
+# Note: This is a helpful reference for identifying the toolchain
+# http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
+
+switch -glob -- [get-define host] {
+ *-*-darwin* {
+ define SHOBJ_CFLAGS "-dynamic -fno-common"
+ define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
+ define SHOBJ_LDFLAGS_R -bundle
+ define SH_CFLAGS -dynamic
+ define SH_LDFLAGS -dynamiclib
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dylib
+ define SH_SOEXTVER .%s.dylib
+ define SH_SOPREFIX -Wl,-install_name,
+ define SH_SOFULLPATH
+ define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+ define STRIPLIBFLAGS -x
+ }
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define SHOBJ_CFLAGS ""
+ define SHOBJ_LDFLAGS -shared
+ define SH_CFLAGS ""
+ define SH_LDFLAGS -shared
+ define SH_LINKRPATH ""
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dll
+ define SH_SOEXTVER .dll
+ define SH_SOPREFIX ""
+ define LD_LIBRARY_PATH PATH
+ }
+ sparc* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ }
+ }
+ *-*-solaris* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ }
+ }
+ *-*-hpux {
+ # XXX: These haven't been tested
+ define SHOBJ_CFLAGS "+O3 +z"
+ define SHOBJ_LDFLAGS -b
+ define SH_CFLAGS +z
+ define SH_LINKFLAGS -Wl,+s
+ define LD_LIBRARY_PATH SHLIB_PATH
+ }
+ *-*-haiku {
+ define SHOBJ_CFLAGS ""
+ define SHOBJ_LDFLAGS -shared
+ define SH_CFLAGS ""
+ define SH_LDFLAGS -shared
+ define SH_LINKFLAGS ""
+ define SH_SOPREFIX ""
+ define LD_LIBRARY_PATH LIBRARY_PATH
+ }
+}
+
+if {![is-defined SHOBJ_LDFLAGS_R]} {
+ define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
+}
diff --git a/autosetup/cc.tcl b/autosetup/cc.tcl
new file mode 100644
index 0000000000..05c1b1cf40
--- /dev/null
+++ b/autosetup/cc.tcl
@@ -0,0 +1,758 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc' module supports checking various 'features' of the C or C++
+# compiler/linker environment. Common commands are 'cc-check-includes',
+# 'cc-check-types', 'cc-check-functions', 'cc-with' and 'make-config-header'
+#
+# The following environment variables are used if set:
+#
+## CC - C compiler
+## CXX - C++ compiler
+## CPP - C preprocessor
+## CCACHE - Set to "none" to disable automatic use of ccache
+## CPPFLAGS - Additional C preprocessor compiler flags (C and C++), before CFLAGS, CXXFLAGS
+## CFLAGS - Additional C compiler flags
+## CXXFLAGS - Additional C++ compiler flags
+## LDFLAGS - Additional compiler flags during linking
+## LINKFLAGS - ?How is this different from LDFLAGS?
+## LIBS - Additional libraries to use (for all tests)
+## CROSS - Tool prefix for cross compilation
+#
+# The following variables are defined from the corresponding
+# environment variables if set.
+#
+## CC_FOR_BUILD
+## LD
+
+use system
+
+options {}
+
+# Checks for the existence of the given function by linking
+#
+proc cctest_function {function} {
+ cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
+}
+
+# Checks for the existence of the given type by compiling
+proc cctest_type {type} {
+ cctest -code "$type _x;"
+}
+
+# Checks for the existence of the given type/structure member.
+# e.g. "struct stat.st_mtime"
+proc cctest_member {struct_member} {
+ # split at the first dot
+ regexp {^([^.]+)[.](.*)$} $struct_member -> struct member
+ cctest -code "static $struct _s; return sizeof(_s.$member);"
+}
+
+# Checks for the existence of the given define by compiling
+#
+proc cctest_define {name} {
+ cctest -code "#ifndef $name\n#error not defined\n#endif"
+}
+
+# Checks for the existence of the given name either as
+# a macro (#define) or an rvalue (such as an enum)
+#
+proc cctest_decl {name} {
+ cctest -code "#ifndef $name\n(void)$name;\n#endif"
+}
+
+# @cc-check-sizeof type ...
+#
+# Checks the size of the given types (between 1 and 32, inclusive).
+# Defines a variable with the size determined, or 'unknown' otherwise.
+# e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
+# Returns the size of the last type.
+#
+proc cc-check-sizeof {args} {
+ foreach type $args {
+ msg-checking "Checking for sizeof $type..."
+ set size unknown
+ # Try the most common sizes first
+ foreach i {4 8 1 2 16 32} {
+ if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
+ set size $i
+ break
+ }
+ }
+ msg-result $size
+ set define [feature-define-name $type SIZEOF_]
+ define $define $size
+ }
+ # Return the last result
+ get-define $define
+}
+
+# Checks for each feature in $list by using the given script.
+#
+# When the script is evaluated, $each is set to the feature
+# being checked, and $extra is set to any additional cctest args.
+#
+# Returns 1 if all features were found, or 0 otherwise.
+proc cc-check-some-feature {list script} {
+ set ret 1
+ foreach each $list {
+ if {![check-feature $each $script]} {
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-includes includes ...
+#
+# Checks that the given include files can be used.
+proc cc-check-includes {args} {
+ cc-check-some-feature $args {
+ set with {}
+ if {[dict exists $::autosetup(cc-include-deps) $each]} {
+ set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
+ msg-quiet cc-check-includes {*}$deps
+ foreach i $deps {
+ if {[have-feature $i]} {
+ lappend with $i
+ }
+ }
+ }
+ if {[llength $with]} {
+ cc-with [list -includes $with] {
+ cctest -includes $each
+ }
+ } else {
+ cctest -includes $each
+ }
+ }
+}
+
+# @cc-include-needs include required ...
+#
+# Ensures that when checking for '$include', a check is first
+# made for each '$required' file, and if found, it is included with '#include'.
+proc cc-include-needs {file args} {
+ foreach depfile $args {
+ dict set ::autosetup(cc-include-deps) $file $depfile 1
+ }
+}
+
+# @cc-check-types type ...
+#
+# Checks that the types exist.
+proc cc-check-types {args} {
+ cc-check-some-feature $args {
+ cctest_type $each
+ }
+}
+
+# @cc-check-defines define ...
+#
+# Checks that the given preprocessor symbols are defined.
+proc cc-check-defines {args} {
+ cc-check-some-feature $args {
+ cctest_define $each
+ }
+}
+
+# @cc-check-decls name ...
+#
+# Checks that each given name is either a preprocessor symbol or rvalue
+# such as an enum. Note that the define used is 'HAVE_DECL_xxx'
+# rather than 'HAVE_xxx'.
+proc cc-check-decls {args} {
+ set ret 1
+ foreach name $args {
+ msg-checking "Checking for $name..."
+ set r [cctest_decl $name]
+ define-feature "decl $name" $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-functions function ...
+#
+# Checks that the given functions exist (can be linked).
+proc cc-check-functions {args} {
+ cc-check-some-feature $args {
+ cctest_function $each
+ }
+}
+
+# @cc-check-members type.member ...
+#
+# Checks that the given type/structure members exist.
+# A structure member is of the form 'struct stat.st_mtime'.
+proc cc-check-members {args} {
+ cc-check-some-feature $args {
+ cctest_member $each
+ }
+}
+
+# @cc-check-function-in-lib function libs ?otherlibs?
+#
+# Checks that the given function can be found in one of the libs.
+#
+# First checks for no library required, then checks each of the libraries
+# in turn.
+#
+# If the function is found, the feature is defined and 'lib_$function' is defined
+# to '-l$lib' where the function was found, or "" if no library required.
+# In addition, '-l$lib' is prepended to the 'LIBS' define.
+#
+# If additional libraries may be needed for linking, they should be specified
+# with '$extralibs' as '-lotherlib1 -lotherlib2'.
+# These libraries are not automatically added to 'LIBS'.
+#
+# Returns 1 if found or 0 if not.
+#
+proc cc-check-function-in-lib {function libs {otherlibs {}}} {
+ msg-checking "Checking libs for $function..."
+ set found 0
+ cc-with [list -libs $otherlibs] {
+ if {[cctest_function $function]} {
+ msg-result "none needed"
+ define lib_$function ""
+ incr found
+ } else {
+ foreach lib $libs {
+ cc-with [list -libs -l$lib] {
+ if {[cctest_function $function]} {
+ msg-result -l$lib
+ define lib_$function -l$lib
+ # prepend to LIBS
+ define LIBS "-l$lib [get-define LIBS]"
+ incr found
+ break
+ }
+ }
+ }
+ }
+ }
+ define-feature $function $found
+ if {!$found} {
+ msg-result "no"
+ }
+ return $found
+}
+
+# @cc-check-tools tool ...
+#
+# Checks for existence of the given compiler tools, taking
+# into account any cross compilation prefix.
+#
+# For example, when checking for 'ar', first 'AR' is checked on the command
+# line and then in the environment. If not found, '${host}-ar' or
+# simply 'ar' is assumed depending upon whether cross compiling.
+# The path is searched for this executable, and if found 'AR' is defined
+# to the executable name.
+# Note that even when cross compiling, the simple 'ar' is used as a fallback,
+# but a warning is generated. This is necessary for some toolchains.
+#
+# It is an error if the executable is not found.
+#
+proc cc-check-tools {args} {
+ foreach tool $args {
+ set TOOL [string toupper $tool]
+ set exe [get-env $TOOL [get-define cross]$tool]
+ if {[find-executable $exe]} {
+ define $TOOL $exe
+ continue
+ }
+ if {[find-executable $tool]} {
+ msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
+ define $TOOL $tool
+ continue
+ }
+ user-error "Failed to find $exe"
+ }
+}
+
+# @cc-check-progs prog ...
+#
+# Checks for existence of the given executables on the path.
+#
+# For example, when checking for 'grep', the path is searched for
+# the executable, 'grep', and if found 'GREP' is defined as 'grep'.
+#
+# If the executable is not found, the variable is defined as 'false'.
+# Returns 1 if all programs were found, or 0 otherwise.
+#
+proc cc-check-progs {args} {
+ set failed 0
+ foreach prog $args {
+ set PROG [string toupper $prog]
+ msg-checking "Checking for $prog..."
+ if {![find-executable $prog]} {
+ msg-result no
+ define $PROG false
+ incr failed
+ } else {
+ msg-result ok
+ define $PROG $prog
+ }
+ }
+ expr {!$failed}
+}
+
+# @cc-path-progs prog ...
+#
+# Like cc-check-progs, but sets the define to the full path rather
+# than just the program name.
+#
+proc cc-path-progs {args} {
+ set failed 0
+ foreach prog $args {
+ set PROG [string toupper $prog]
+ msg-checking "Checking for $prog..."
+ set path [find-executable-path $prog]
+ if {$path eq ""} {
+ msg-result no
+ define $PROG false
+ incr failed
+ } else {
+ msg-result $path
+ define $PROG $path
+ }
+ }
+ expr {!$failed}
+}
+
+# Adds the given settings to $::autosetup(ccsettings) and
+# returns the old settings.
+#
+proc cc-add-settings {settings} {
+ if {[llength $settings] % 2} {
+ autosetup-error "settings list is missing a value: $settings"
+ }
+
+ set prev [cc-get-settings]
+ # workaround a bug in some versions of jimsh by forcing
+ # conversion of $prev to a list
+ llength $prev
+
+ array set new $prev
+
+ foreach {name value} $settings {
+ switch -exact -- $name {
+ -cflags - -includes {
+ # These are given as lists
+ lappend new($name) {*}[list-non-empty $value]
+ }
+ -declare {
+ lappend new($name) $value
+ }
+ -libs {
+ # Note that new libraries are added before previous libraries
+ set new($name) [list {*}[list-non-empty $value] {*}$new($name)]
+ }
+ -link - -lang - -nooutput {
+ set new($name) $value
+ }
+ -source - -sourcefile - -code {
+ # XXX: These probably are only valid directly from cctest
+ set new($name) $value
+ }
+ default {
+ autosetup-error "unknown cctest setting: $name"
+ }
+ }
+ }
+
+ cc-store-settings [array get new]
+
+ return $prev
+}
+
+proc cc-store-settings {new} {
+ set ::autosetup(ccsettings) $new
+}
+
+proc cc-get-settings {} {
+ return $::autosetup(ccsettings)
+}
+
+# Similar to cc-add-settings, but each given setting
+# simply replaces the existing value.
+#
+# Returns the previous settings
+proc cc-update-settings {args} {
+ set prev [cc-get-settings]
+ cc-store-settings [dict merge $prev $args]
+ return $prev
+}
+
+# @cc-with settings ?{ script }?
+#
+# Sets the given 'cctest' settings and then runs the tests in '$script'.
+# Note that settings such as '-lang' replace the current setting, while
+# those such as '-includes' are appended to the existing setting.
+#
+# If no script is given, the settings become the default for the remainder
+# of the 'auto.def' file.
+#
+## cc-with {-lang c++} {
+## # This will check with the C++ compiler
+## cc-check-types bool
+## cc-with {-includes signal.h} {
+## # This will check with the C++ compiler, signal.h and any existing includes.
+## ...
+## }
+## # back to just the C++ compiler
+## }
+#
+# The '-libs' setting is special in that newer values are added *before* earlier ones.
+#
+## cc-with {-libs {-lc -lm}} {
+## cc-with {-libs -ldl} {
+## cctest -libs -lsocket ...
+## # libs will be in this order: -lsocket -ldl -lc -lm
+## }
+## }
+#
+# If you wish to invoke something like cc-check-flags but not have -cflags updated,
+# use the following idiom:
+#
+## cc-with {} {
+## cc-check-flags ...
+## }
+proc cc-with {settings args} {
+ if {[llength $args] == 0} {
+ cc-add-settings $settings
+ } elseif {[llength $args] > 1} {
+ autosetup-error "usage: cc-with settings ?script?"
+ } else {
+ set save [cc-add-settings $settings]
+ set rc [catch {uplevel 1 [lindex $args 0]} result info]
+ cc-store-settings $save
+ if {$rc != 0} {
+ return -code [dict get $info -code] $result
+ }
+ return $result
+ }
+}
+
+# @cctest ?settings?
+#
+# Low level C/C++ compiler checker. Compiles and or links a small C program
+# according to the arguments and returns 1 if OK, or 0 if not.
+#
+# Supported settings are:
+#
+## -cflags cflags A list of flags to pass to the compiler
+## -includes list A list of includes, e.g. {stdlib.h stdio.h}
+## -declare code Code to declare before main()
+## -link 1 Don't just compile, link too
+## -lang c|c++ Use the C (default) or C++ compiler
+## -libs liblist List of libraries to link, e.g. {-ldl -lm}
+## -code code Code to compile in the body of main()
+## -source code Compile a complete program. Ignore -includes, -declare and -code
+## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
+## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
+#
+# Unless '-source' or '-sourcefile' is specified, the C program looks like:
+#
+## #include /* same for remaining includes in the list */
+## declare-code /* any code in -declare, verbatim */
+## int main(void) {
+## code /* any code in -code, verbatim */
+## return 0;
+## }
+#
+# And the command line looks like:
+#
+## CC -cflags CFLAGS CPPFLAGS conftest.c -o conftest.o
+## CXX -cflags CXXFLAGS CPPFLAGS conftest.cpp -o conftest.o
+#
+# And if linking:
+#
+## CC LDFLAGS -cflags CFLAGS conftest.c -o conftest -libs LIBS
+## CXX LDFLAGS -cflags CXXFLAGS conftest.c -o conftest -libs LIBS
+#
+# Any failures are recorded in 'config.log'
+#
+proc cctest {args} {
+ set tmp conftest__
+
+ # Easiest way to merge in the settings
+ cc-with $args {
+ array set opts [cc-get-settings]
+ }
+
+ if {[info exists opts(-sourcefile)]} {
+ set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
+ }
+ if {[info exists opts(-source)]} {
+ set lines $opts(-source)
+ } else {
+ foreach i $opts(-includes) {
+ if {$opts(-code) ne "" && ![feature-checked $i]} {
+ # Compiling real code with an unchecked header file
+ # Quickly (and silently) check for it now
+
+ # Remove all -includes from settings before checking
+ set saveopts [cc-update-settings -includes {}]
+ msg-quiet cc-check-includes $i
+ cc-store-settings $saveopts
+ }
+ if {$opts(-code) eq "" || [have-feature $i]} {
+ lappend source "#include <$i>"
+ }
+ }
+ lappend source {*}$opts(-declare)
+ lappend source "int main(void) {"
+ lappend source $opts(-code)
+ lappend source "return 0;"
+ lappend source "}"
+
+ set lines [join $source \n]
+ }
+
+ # Build the command line
+ set cmdline {}
+ lappend cmdline {*}[get-define CCACHE]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ set src conftest__.cpp
+ lappend cmdline {*}[get-define CXX]
+ set cflags [get-define CXXFLAGS]
+ }
+ c {
+ set src conftest__.c
+ lappend cmdline {*}[get-define CC]
+ set cflags [get-define CFLAGS]
+ }
+ default {
+ autosetup-error "cctest called with unknown language: $opts(-lang)"
+ }
+ }
+
+ if {$opts(-link)} {
+ lappend cmdline {*}[get-define LDFLAGS]
+ } else {
+ lappend cflags {*}[get-define CPPFLAGS]
+ set tmp conftest__.o
+ lappend cmdline -c
+ }
+ lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""] {*}$cflags
+ lappend cmdline $src -o $tmp
+ if {$opts(-link)} {
+ lappend cmdline {*}$opts(-libs) {*}[get-define LIBS]
+ }
+
+ # At this point we have the complete command line and the
+ # complete source to be compiled. Get the result from cache if
+ # we can
+ if {[info exists ::cc_cache($cmdline,$lines)]} {
+ msg-checking "(cached) "
+ set ok $::cc_cache($cmdline,$lines)
+ if {$::autosetup(debug)} {
+ configlog "From cache (ok=$ok): [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ return $ok
+ }
+
+ writefile $src $lines\n
+
+ set ok 1
+ set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
+ if {$err || ($opts(-nooutput) && [string length $result])} {
+ configlog "Failed: [join $cmdline]"
+ configlog $result
+ configlog "============"
+ configlog "The failed code was:"
+ configlog $lines
+ configlog "============"
+ set ok 0
+ } elseif {$::autosetup(debug)} {
+ configlog "Compiled OK: [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ file delete $src
+ file delete $tmp
+
+ # cache it
+ set ::cc_cache($cmdline,$lines) $ok
+
+ return $ok
+}
+
+# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
+#
+# Deprecated - see 'make-config-header'
+proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
+ user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
+ make-config-header $file -auto $autopatterns -bare $barepatterns
+}
+
+# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
+#
+# Examines all defined variables which match the given patterns
+# and writes an include file, '$file', which defines each of these.
+# Variables which match '-auto' are output as follows:
+# - defines which have the value '0' are ignored.
+# - defines which have integer values are defined as the integer value.
+# - any other value is defined as a string, e.g. '"value"'
+# Variables which match '-bare' are defined as-is.
+# Variables which match '-str' are defined as a string, e.g. '"value"'
+# Variables which match '-none' are omitted.
+#
+# Note that order is important. The first pattern that matches is selected.
+# Default behaviour is:
+#
+## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
+#
+# If the file would be unchanged, it is not written.
+proc make-config-header {file args} {
+ set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
+ file mkdir [file dirname $file]
+ set lines {}
+ lappend lines "#ifndef $guard"
+ lappend lines "#define $guard"
+
+ # Add some defaults
+ lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+
+ foreach n [lsort [dict keys [all-defines]]] {
+ set value [get-define $n]
+ set type [calc-define-output-type $n $args]
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ continue
+ }
+ -str {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ -auto {
+ # Automatically determine the type
+ if {$value eq "0"} {
+ lappend lines "/* #undef $n */"
+ continue
+ }
+ if {![string is integer -strict $value]} {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ }
+ "" {
+ continue
+ }
+ default {
+ autosetup-error "Unknown type in make-config-header: $type"
+ }
+ }
+ lappend lines "#define $n $value"
+ }
+ lappend lines "#endif"
+ set buf [join $lines \n]
+ write-if-changed $file $buf {
+ msg-result "Created $file"
+ }
+}
+
+proc calc-define-output-type {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+proc cc-init {} {
+ global autosetup
+
+ # Initialise some values from the environment or commandline or default settings
+ foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
+ lassign $i var default
+ define $var [get-env $var $default]
+ }
+
+ if {[env-is-set CC]} {
+ # Set by the user, so don't try anything else
+ set try [list [get-env CC ""]]
+ } else {
+ # Try some reasonable options
+ set try [list [get-define cross]cc [get-define cross]gcc]
+ }
+ define CC [find-an-executable {*}$try]
+ if {[get-define CC] eq ""} {
+ user-error "Could not find a C compiler. Tried: [join $try ", "]"
+ }
+
+ define CPP [get-env CPP "[get-define CC] -E"]
+
+ # XXX: Could avoid looking for a C++ compiler until requested
+ # If CXX isn't found, it is set to the empty string.
+ if {[env-is-set CXX]} {
+ define CXX [find-an-executable -required [get-env CXX ""]]
+ } else {
+ define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++]
+ }
+
+ # CXXFLAGS default to CFLAGS if not specified
+ define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+
+ # May need a CC_FOR_BUILD, so look for one
+ define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+
+ # These start empty and never come from the user or environment
+ define AS_CFLAGS ""
+ define AS_CPPFLAGS ""
+ define AS_CXXFLAGS ""
+
+ define CCACHE [find-an-executable [get-env CCACHE ccache]]
+
+ # If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
+ foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
+ if {[env-is-set $i]} {
+ # Note: If the variable is set on the command line, get-env will return that value
+ # so the command line will continue to override the environment
+ define-append-argv AUTOREMAKE $i=[get-env $i ""]
+ }
+ }
+
+ # Initial cctest settings
+ cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
+ set autosetup(cc-include-deps) {}
+
+ msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
+ if {[get-define CXX] ne "false"} {
+ msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
+ }
+ msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+ # On Darwin, we prefer to use -g0 to avoid creating .dSYM directories
+ # but some compilers may not support it, so test here.
+ switch -glob -- [get-define host] {
+ *-*-darwin* {
+ if {[cctest -cflags {-g0}]} {
+ define cc-default-debug -g0
+ }
+ }
+ }
+
+ if {![cc-check-includes stdlib.h]} {
+ user-error "Compiler does not work. See config.log"
+ }
+}
+
+cc-init
diff --git a/autosetup/jimsh0.c b/autosetup/jimsh0.c
new file mode 100644
index 0000000000..1a6453d0c8
--- /dev/null
+++ b/autosetup/jimsh0.c
@@ -0,0 +1,24506 @@
+/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
+#define JIM_COMPAT
+#define JIM_ANSIC
+#define JIM_REGEXP
+#define HAVE_NO_AUTOCONF
+#define JIM_TINY
+#define _JIMAUTOCONF_H
+#define TCL_LIBRARY "."
+#define jim_ext_bootstrap
+#define jim_ext_aio
+#define jim_ext_readdir
+#define jim_ext_regexp
+#define jim_ext_file
+#define jim_ext_glob
+#define jim_ext_exec
+#define jim_ext_clock
+#define jim_ext_array
+#define jim_ext_stdlib
+#define jim_ext_tclcompat
+#if defined(_MSC_VER)
+#define TCL_PLATFORM_OS "windows"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#elif defined(__MINGW32__)
+#define TCL_PLATFORM_OS "mingw"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#define HAVE_UMASK
+#include
+#ifndef S_IRWXG
+#define S_IRWXG 0
+#endif
+#ifndef S_IRWXO
+#define S_IRWXO 0
+#endif
+#else
+#define TCL_PLATFORM_OS "unknown"
+#define TCL_PLATFORM_PLATFORM "unix"
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#ifdef _MINIX
+#define vfork fork
+#define _POSIX_SOURCE
+#else
+#define _GNU_SOURCE
+#endif
+#define HAVE_FORK
+#define HAVE_WAITPID
+#define HAVE_ISATTY
+#define HAVE_MKSTEMP
+#define HAVE_LINK
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#define HAVE_UMASK
+#define HAVE_PIPE
+#define _FILE_OFFSET_BITS 64
+#endif
+#define JIM_VERSION 84
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#if defined(_WIN32) || defined(WIN32)
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+
+#if defined(__MINGW32__)
+ #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
+#endif
+
+#ifdef _MSC_VER
+
+
+#if _MSC_VER >= 1000
+ #pragma warning(disable:4146)
+#endif
+
+#include
+#define jim_wide _int64
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG
+#endif
+#ifndef LLONG_MAX
+ #define LLONG_MAX 9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+ #define LLONG_MIN (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+#define strcasecmp _stricmp
+#define strtoull _strtoui64
+
+#include
+
+#include
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+ char *d_name;
+};
+
+typedef struct DIR {
+ long handle;
+ struct _finddata_t info;
+ struct dirent result;
+ char *name;
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef UTF8_UTIL_H
+#define UTF8_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define MAX_UTF8_LEN 4
+
+int utf8_fromunicode(char *p, unsigned uc);
+
+#ifndef JIM_UTF8
+#include
+
+
+#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
+#define utf8_strwidth(S, B) utf8_strlen((S), (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
+#define utf8_getchars(CP, C) (*(CP) = (C), 1)
+#define utf8_upper(C) toupper(C)
+#define utf8_title(C) toupper(C)
+#define utf8_lower(C) tolower(C)
+#define utf8_index(C, I) (I)
+#define utf8_charlen(C) 1
+#define utf8_prev_len(S, L) 1
+#define utf8_width(C) 1
+
+#else
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+#include
+
+
+#ifndef HAVE_NO_AUTOCONF
+#endif
+
+
+
+#ifndef jim_wide
+# ifdef HAVE_LONG_LONG
+# define jim_wide long long
+# ifndef LLONG_MAX
+# define LLONG_MAX 9223372036854775807LL
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# endif
+# define JIM_WIDE_MIN LLONG_MIN
+# define JIM_WIDE_MAX LLONG_MAX
+# else
+# define jim_wide long
+# define JIM_WIDE_MIN LONG_MIN
+# define JIM_WIDE_MAX LONG_MAX
+# endif
+
+
+# ifdef HAVE_LONG_LONG
+# define JIM_WIDE_MODIFIER "lld"
+# else
+# define JIM_WIDE_MODIFIER "ld"
+# define strtoull strtoul
+# endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+
+
+#define JIM_ABI_VERSION 101
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+
+#define JIM_EVAL 7
+
+#define JIM_MAX_CALLFRAME_DEPTH 1000
+#define JIM_MAX_EVAL_DEPTH 2000
+
+
+#define JIM_PRIV_FLAG_SHIFT 20
+
+#define JIM_NONE 0
+#define JIM_ERRMSG 1
+#define JIM_ENUM_ABBREV 2
+#define JIM_UNSHARED 4
+#define JIM_MUSTEXIST 8
+#define JIM_NORESULT 16
+
+
+#define JIM_SUBST_NOVAR 1
+#define JIM_SUBST_NOCMD 2
+#define JIM_SUBST_NOESC 4
+#define JIM_SUBST_FLAG 128
+
+
+#define JIM_CASESENS 0
+#define JIM_NOCASE 1
+#define JIM_OPT_END 2
+
+
+#define JIM_PATH_LEN 1024
+
+
+#define JIM_NOTUSED(V) ((void) V)
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+
+typedef struct Jim_Stack {
+ int len;
+ int maxlen;
+ void **vector;
+} Jim_Stack;
+
+
+typedef struct Jim_HashEntry {
+ void *key;
+ union {
+ void *val;
+ int intval;
+ } u;
+ struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+ unsigned int (*hashFunction)(const void *key);
+ void *(*keyDup)(void *privdata, const void *key);
+ void *(*valDup)(void *privdata, const void *obj);
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+ void (*keyDestructor)(void *privdata, void *key);
+ void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+ Jim_HashEntry **table;
+ const Jim_HashTableType *type;
+ void *privdata;
+ unsigned int size;
+ unsigned int sizemask;
+ unsigned int used;
+ unsigned int collisions;
+ unsigned int uniq;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+ Jim_HashTable *ht;
+ Jim_HashEntry *entry, *nextEntry;
+ int index;
+} Jim_HashTableIterator;
+
+
+#define JIM_HT_INITIAL_SIZE 16
+
+
+#define Jim_FreeEntryVal(ht, entry) \
+ if ((ht)->type->valDestructor) \
+ (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+ if ((ht)->type->valDup) \
+ (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
+ else \
+ (entry)->u.val = (_val_); \
+} while(0)
+
+#define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_)
+
+#define Jim_FreeEntryKey(ht, entry) \
+ if ((ht)->type->keyDestructor) \
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+ if ((ht)->type->keyDup) \
+ (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
+ else \
+ (entry)->key = (void *)(_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+ (((ht)->type->keyCompare) ? \
+ (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
+ (key1) == (key2))
+
+#define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->u.val)
+#define Jim_GetHashEntryIntVal(he) ((he)->u.intval)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+
+typedef struct Jim_Obj {
+ char *bytes;
+ const struct Jim_ObjType *typePtr;
+ int refCount;
+ int length;
+
+ union {
+
+ jim_wide wideValue;
+
+ int intValue;
+
+ double doubleValue;
+
+ void *ptr;
+
+ struct {
+ void *ptr1;
+ void *ptr2;
+ } twoPtrValue;
+
+ struct {
+ void *ptr;
+ int int1;
+ int int2;
+ } ptrIntValue;
+
+ struct {
+ struct Jim_VarVal *vv;
+ unsigned long callFrameId;
+ int global;
+ } varValue;
+
+ struct {
+ struct Jim_Obj *nsObj;
+ struct Jim_Cmd *cmdPtr;
+ unsigned long procEpoch;
+ } cmdValue;
+
+ struct {
+ struct Jim_Obj **ele;
+ int len;
+ int maxLen;
+ } listValue;
+
+ struct Jim_Dict *dictValue;
+
+ struct {
+ int maxLength;
+ int charLength;
+ } strValue;
+
+ struct {
+ unsigned long id;
+ struct Jim_Reference *refPtr;
+ } refValue;
+
+ struct {
+ struct Jim_Obj *fileNameObj;
+ int lineNumber;
+ } sourceValue;
+
+ struct {
+ struct Jim_Obj *varNameObjPtr;
+ struct Jim_Obj *indexObjPtr;
+ } dictSubstValue;
+ struct {
+ int line;
+ int argc;
+ } scriptLineValue;
+ } internalRep;
+ struct Jim_Obj *prevObjPtr;
+ struct Jim_Obj *nextObjPtr;
+} Jim_Obj;
+
+
+#define Jim_IncrRefCount(objPtr) \
+ ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+ if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+ ((objPtr)->refCount > 1)
+
+#define Jim_FreeNewObj Jim_FreeObj
+
+
+#define Jim_FreeIntRep(i,o) \
+ if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+ (o)->typePtr->freeIntRepProc(i, o)
+
+
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+
+#define Jim_SetIntRepPtr(o, p) \
+ (o)->internalRep.ptr = (p)
+
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+ const char *name;
+ Jim_FreeInternalRepProc *freeIntRepProc;
+ Jim_DupInternalRepProc *dupIntRepProc;
+ Jim_UpdateStringProc *updateStringProc;
+ int flags;
+} Jim_ObjType;
+
+
+#define JIM_TYPE_NONE 0
+#define JIM_TYPE_REFERENCES 1
+
+
+
+typedef struct Jim_CallFrame {
+ unsigned long id;
+ int level;
+ struct Jim_HashTable vars;
+ struct Jim_HashTable *staticVars;
+ struct Jim_CallFrame *parent;
+ Jim_Obj *const *argv;
+ int argc;
+ Jim_Obj *procArgsObjPtr;
+ Jim_Obj *procBodyObjPtr;
+ struct Jim_CallFrame *next;
+ Jim_Obj *nsObj;
+ Jim_Obj *unused_fileNameObj;
+ int unused_line;
+ Jim_Stack *localCommands;
+ struct Jim_Obj *tailcallObj;
+ struct Jim_Cmd *tailcallCmd;
+} Jim_CallFrame;
+
+
+typedef struct Jim_EvalFrame {
+ Jim_CallFrame *framePtr;
+ int level;
+ int procLevel;
+ struct Jim_Cmd *cmd;
+ struct Jim_EvalFrame *parent;
+ Jim_Obj *const *argv;
+ int argc;
+ Jim_Obj *scriptObj;
+} Jim_EvalFrame;
+
+typedef struct Jim_VarVal {
+ Jim_Obj *objPtr;
+ struct Jim_CallFrame *linkFramePtr;
+ int refCount;
+} Jim_VarVal;
+
+
+typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv);
+typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
+
+typedef struct Jim_Dict {
+ struct JimDictHashEntry {
+ int offset;
+ unsigned hash;
+ } *ht;
+ unsigned int size;
+ unsigned int sizemask;
+ unsigned int uniq;
+ Jim_Obj **table;
+ int len;
+ int maxLen;
+ unsigned int dummy;
+} Jim_Dict;
+
+typedef struct Jim_Cmd {
+ int inUse;
+ int isproc;
+ struct Jim_Cmd *prevCmd;
+ Jim_Obj *cmdNameObj;
+ union {
+ struct {
+
+ Jim_CmdProc *cmdProc;
+ Jim_DelCmdProc *delProc;
+ void *privData;
+ } native;
+ struct {
+
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_HashTable *staticVars;
+ int argListLen;
+ int reqArity;
+ int optArity;
+ int argsPos;
+ int upcall;
+ struct Jim_ProcArg {
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ } *arglist;
+ Jim_Obj *nsObj;
+ } proc;
+ } u;
+} Jim_Cmd;
+
+
+typedef struct Jim_PrngState {
+ unsigned char sbox[256];
+ unsigned int i, j;
+} Jim_PrngState;
+
+typedef struct Jim_Interp {
+ Jim_Obj *result;
+ int unused_errorLine;
+ Jim_Obj *currentFilenameObj;
+ int break_level;
+ int maxCallFrameDepth;
+ int maxEvalDepth;
+ int evalDepth;
+ int returnCode;
+ int returnLevel;
+ int exitCode;
+ long id;
+ int signal_level;
+ jim_wide sigmask;
+ int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
+ Jim_CallFrame *framePtr;
+ Jim_CallFrame *topFramePtr;
+ struct Jim_HashTable commands;
+ unsigned long procEpoch; /* Incremented every time the result
+ of procedures names lookup caching
+ may no longer be valid. */
+ unsigned long callFrameEpoch; /* Incremented every time a new
+ callframe is created. This id is used for the
+ 'ID' field contained in the Jim_CallFrame
+ structure. */
+ int local;
+ int quitting;
+ int safeexpr;
+ Jim_Obj *liveList;
+ Jim_Obj *freeList;
+ Jim_Obj *unused_currentScriptObj;
+ Jim_EvalFrame topEvalFrame;
+ Jim_EvalFrame *evalFrame;
+ int procLevel;
+ Jim_Obj * const *unused_argv;
+ Jim_Obj *nullScriptObj;
+ Jim_Obj *emptyObj;
+ Jim_Obj *trueObj;
+ Jim_Obj *falseObj;
+ unsigned long referenceNextId;
+ struct Jim_HashTable references;
+ unsigned long lastCollectId; /* reference max Id of the last GC
+ execution. It's set to ~0 while the collection
+ is running as sentinel to avoid to recursive
+ calls via the [collect] command inside
+ finalizers. */
+ jim_wide lastCollectTime;
+ Jim_Obj *stackTrace;
+ Jim_Obj *errorProc;
+ Jim_Obj *unknown;
+ Jim_Obj *defer;
+ Jim_Obj *traceCmdObj;
+ int unknown_called;
+ int errorFlag;
+ void *cmdPrivData; /* Used to pass the private data pointer to
+ a command. It is set to what the user specified
+ via Jim_CreateCommand(). */
+
+ Jim_Cmd *oldCmdCache;
+ int oldCmdCacheSize;
+ struct Jim_CallFrame *freeFramesList;
+ struct Jim_HashTable assocData;
+ Jim_PrngState *prngState;
+ struct Jim_HashTable packages;
+ Jim_Stack *loadHandles;
+} Jim_Interp;
+
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+
+#define Jim_SetResult(i,o) do { \
+ Jim_Obj *_resultObjPtr_ = (o); \
+ Jim_IncrRefCount(_resultObjPtr_); \
+ Jim_DecrRefCount(i,(i)->result); \
+ (i)->result = _resultObjPtr_; \
+} while(0)
+
+
+#define Jim_GetId(i) (++(i)->id)
+
+
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+ string representation must be fixed length. */
+typedef struct Jim_Reference {
+ Jim_Obj *objPtr;
+ Jim_Obj *finalizerCmdNamePtr;
+ char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT extern
+
+
+
+JIM_EXPORT void *(*Jim_Allocator)(void *ptr, size_t size);
+
+#define Jim_Free(P) Jim_Allocator((P), 0)
+#define Jim_Realloc(P, S) Jim_Allocator((P), (S))
+#define Jim_Alloc(S) Jim_Allocator(NULL, (S))
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+#endif
+#ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
+
+
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+
+
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+ int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+ Jim_Obj **resObjPtrPtr, int flags);
+
+
+JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *lineptr);
+
+JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber);
+
+
+
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+ const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht,
+ unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+ void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+ const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+ (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+ (Jim_HashTableIterator *iter);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+ int *lenPtr);
+JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+ const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+ const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+ char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+ Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+ Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+ Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+ Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+ Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+ Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+ Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+ const char *cmdName, Jim_CmdProc *cmdProc, void *privData,
+ Jim_DelCmdProc *delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+ Jim_Obj *cmdNameObj);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+ Jim_Obj *oldNameObj, Jim_Obj *newNameObj);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+ Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+ const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+ Jim_CallFrame *targetCallFrame);
+JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp,
+ Jim_Obj *nameObjPtr);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+
+
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+ Jim_Obj *levelObjPtr);
+
+
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *indexPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+ Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+ int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+ Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp,
+ Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+ Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT Jim_Obj **Jim_DictPairs(Jim_Interp *interp,
+ Jim_Obj *dictPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+
+#define JIM_DICTMATCH_KEYS 0x0001
+#define JIM_DICTMATCH_VALUES 0x002
+
+JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
+
+
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *intPtr);
+
+
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr, int *boolPtr);
+
+
+JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
+ int *booleanPtr);
+
+
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+ jim_wide *widePtr);
+JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr,
+ jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+ long *longPtr);
+#define Jim_NewWideObj Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+ jim_wide wideValue);
+
+
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *const *tablePtr);
+JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
+ Jim_Obj *scriptObj, char *stateCharPtr);
+
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+ Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version);
+
+
+
+
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+ const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+ const char *name, int flags);
+#define Jim_PackageProvideCheck(INTERP, NAME) \
+ if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \
+ return JIM_ERR
+
+
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+JIM_EXPORT void Jim_HistoryLoad(const char *filename);
+JIM_EXPORT void Jim_HistorySave(const char *filename);
+JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
+JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj);
+JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj);
+JIM_EXPORT void Jim_HistoryAdd(const char *line);
+JIM_EXPORT void Jim_HistoryShow(void);
+JIM_EXPORT void Jim_HistorySetMaxLen(int length);
+JIM_EXPORT int Jim_HistoryGetMaxLen(void);
+
+
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+JIM_EXPORT int Jim_IsBigEndian(void);
+
+#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
+JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask);
+
+
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define JIM_MODFLAG_HIDDEN 0x0001
+#define JIM_MODFLAG_FULLARGV 0x0002
+
+
+
+typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+ const char *cmd;
+ const char *args;
+ jim_subcmd_function *function;
+ short minargs;
+ short maxargs;
+ unsigned short flags;
+} jim_subcmd_type;
+
+#define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs }
+#define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN }
+
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIMREGEXP_H
+#define JIMREGEXP_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+
+typedef struct {
+ int rm_so;
+ int rm_eo;
+} regmatch_t;
+
+
+typedef struct regexp {
+
+ int re_nsub;
+
+
+ int cflags;
+ int err;
+ int regstart;
+ int reganch;
+ int regmust;
+ int regmlen;
+ int *program;
+
+
+ const char *regparse;
+ int p;
+ int proglen;
+
+
+ int eflags;
+ const char *start;
+ const char *reginput;
+ const char *regbol;
+
+
+ regmatch_t *pmatch;
+ int nmatch;
+} regexp;
+
+typedef regexp regex_t;
+
+#define REG_EXTENDED 0
+#define REG_NEWLINE 1
+#define REG_ICASE 2
+
+#define REG_NOTBOL 16
+
+enum {
+ REG_NOERROR,
+ REG_NOMATCH,
+ REG_BADPAT,
+ REG_ERR_NULL_ARGUMENT,
+ REG_ERR_UNKNOWN,
+ REG_ERR_TOO_BIG,
+ REG_ERR_NOMEM,
+ REG_ERR_TOO_MANY_PAREN,
+ REG_ERR_UNMATCHED_PAREN,
+ REG_ERR_UNMATCHED_BRACES,
+ REG_ERR_BAD_COUNT,
+ REG_ERR_JUNK_ON_END,
+ REG_ERR_OPERAND_COULD_BE_EMPTY,
+ REG_ERR_NESTED_COUNT,
+ REG_ERR_INTERNAL,
+ REG_ERR_COUNT_FOLLOWS_NOTHING,
+ REG_ERR_INVALID_ESCAPE,
+ REG_ERR_CORRUPTED,
+ REG_ERR_NULL_CHAR,
+ REG_ERR_UNMATCHED_BRACKET,
+ REG_ERR_NUM
+};
+
+int jim_regcomp(regex_t *preg, const char *regex, int cflags);
+int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
+void jim_regfree(regex_t *preg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIM_SIGNAL_H
+#define JIM_SIGNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char *Jim_SignalId(int sig);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIMIOCOMPAT_H
+#define JIMIOCOMPAT_H
+
+
+#include
+#include
+#include
+
+
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
+
+int Jim_OpenForWrite(const char *filename, int append);
+
+int Jim_OpenForRead(const char *filename);
+
+#if defined(__MINGW32__) || defined(_WIN32)
+ #ifndef STRICT
+ #define STRICT
+ #endif
+ #define WIN32_LEAN_AND_MEAN
+ #include
+ #include
+ #include
+ #include
+
+ typedef HANDLE phandle_t;
+ #define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE
+
+
+ #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
+ #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
+ #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
+ #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
+ #define WNOHANG 1
+
+ int Jim_Errno(void);
+
+ long waitpid(phandle_t phandle, int *status, int nohang);
+
+ phandle_t JimWaitPid(long processid, int *status, int nohang);
+
+ long JimProcessPid(phandle_t phandle);
+
+ #define HAVE_PIPE
+ #define pipe(P) _pipe((P), 0, O_NOINHERIT)
+
+ typedef struct __stat64 jim_stat_t;
+ #define Jim_Stat _stat64
+ #define Jim_FileStat _fstat64
+ #define Jim_Lseek _lseeki64
+ #define O_TEXT _O_TEXT
+ #define O_BINARY _O_BINARY
+ #define Jim_SetMode _setmode
+ #ifndef STDIN_FILENO
+ #define STDIN_FILENO 0
+ #endif
+
+#else
+ #if defined(HAVE_STAT64)
+ typedef struct stat64 jim_stat_t;
+ #define Jim_Stat stat64
+ #if defined(HAVE_FSTAT64)
+ #define Jim_FileStat fstat64
+ #endif
+ #if defined(HAVE_LSTAT64)
+ #define Jim_LinkStat lstat64
+ #endif
+ #else
+ typedef struct stat jim_stat_t;
+ #define Jim_Stat stat
+ #if defined(HAVE_FSTAT)
+ #define Jim_FileStat fstat
+ #endif
+ #if defined(HAVE_LSTAT)
+ #define Jim_LinkStat lstat
+ #endif
+ #endif
+ #if defined(HAVE_LSEEK64)
+ #define Jim_Lseek lseek64
+ #else
+ #define Jim_Lseek lseek
+ #endif
+
+ #if defined(HAVE_UNISTD_H)
+ #include
+ #include
+ #include
+
+ typedef int phandle_t;
+ #define Jim_Errno() errno
+ #define JIM_BAD_PHANDLE -1
+ #define JimProcessPid(PIDTYPE) (PIDTYPE)
+ #define JimWaitPid waitpid
+
+ #ifndef HAVE_EXECVPE
+ #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
+ #endif
+ #endif
+
+ #ifndef O_TEXT
+ #define O_TEXT 0
+ #endif
+
+#endif
+
+# ifndef MAXPATHLEN
+# ifdef PATH_MAX
+# define MAXPATHLEN PATH_MAX
+# else
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+# endif
+
+
+int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb);
+
+#endif
+int Jim_bootstrapInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "bootstrap.tcl", 1,
+"\n"
+"proc package {cmd args} {\n"
+" if {$cmd eq \"require\"} {\n"
+" foreach path $::auto_path {\n"
+" lassign $args pkg\n"
+" set pkgpath $path/$pkg.tcl\n"
+" if {$path eq \".\"} {\n"
+" set pkgpath $pkg.tcl\n"
+" }\n"
+" if {[file exists $pkgpath]} {\n"
+" tailcall uplevel #0 [list source $pkgpath]\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"set tcl_platform(bootstrap) 1\n"
+);
+}
+int Jim_initjimshInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "initjimsh.tcl", 1,
+"\n"
+"\n"
+"\n"
+"proc _jimsh_init {} {\n"
+" rename _jimsh_init {}\n"
+" global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
+"\n"
+"\n"
+" if {[exists jim::argv0]} {\n"
+" if {[string match \"*/*\" $jim::argv0]} {\n"
+" set jim::exe [file join [pwd] $jim::argv0]\n"
+" } else {\n"
+" set jim::argv0 [file tail $jim::argv0]\n"
+" set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n"
+" if {$tcl_platform(platform) eq \"windows\"} {\n"
+"\n"
+" set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n"
+" }\n"
+" foreach p $path {\n"
+" set exec [file join [pwd] $p $jim::argv0]\n"
+" if {[file executable $exec]} {\n"
+" set jim::exe $exec\n"
+" break\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+"\n"
+" lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
+" if {[exists jim::exe]} {\n"
+" lappend p [file dirname $jim::exe]\n"
+" }\n"
+" lappend p {*}$auto_path\n"
+" set auto_path $p\n"
+"\n"
+" if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
+" foreach src {.jimrc jimrc.tcl} {\n"
+" if {[file exists [env HOME]/$src]} {\n"
+" uplevel #0 source [env HOME]/$src\n"
+" break\n"
+" }\n"
+" }\n"
+" }\n"
+" return \"\"\n"
+"}\n"
+"\n"
+"if {$tcl_platform(platform) eq \"windows\"} {\n"
+" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
+"\n"
+"\n"
+"\n"
+"proc tcl::autocomplete {prefix} {\n"
+" if {[set space [string first \" \" $prefix]] != -1} {\n"
+" set cmd [string range $prefix 0 $space-1]\n"
+" if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
+" set arg [string range $prefix $space+1 end]\n"
+"\n"
+" return [lmap p [$cmd -commands] {\n"
+" if {![string match \"${arg}*\" $p]} continue\n"
+" function \"$cmd $p\"\n"
+" }]\n"
+" }\n"
+" }\n"
+"\n"
+" if {[string match \"source *\" $prefix]} {\n"
+" set path [string range $prefix 7 end]\n"
+" return [lmap p [glob -nocomplain \"${path}*\"] {\n"
+" function \"source $p\"\n"
+" }]\n"
+" }\n"
+"\n"
+" return [lmap p [lsort [info commands $prefix*]] {\n"
+" if {[string match \"* *\" $p]} {\n"
+" continue\n"
+" }\n"
+" function $p\n"
+" }]\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
+"\n"
+"set tcl::stdhint_cols {\n"
+" none {0}\n"
+" black {30}\n"
+" red {31}\n"
+" green {32}\n"
+" yellow {33}\n"
+" blue {34}\n"
+" purple {35}\n"
+" cyan {36}\n"
+" normal {37}\n"
+" grey {30 1}\n"
+" gray {30 1}\n"
+" lred {31 1}\n"
+" lgreen {32 1}\n"
+" lyellow {33 1}\n"
+" lblue {34 1}\n"
+" lpurple {35 1}\n"
+" lcyan {36 1}\n"
+" white {37 1}\n"
+"}\n"
+"\n"
+"\n"
+"set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
+"\n"
+"\n"
+"proc tcl::stdhint {string} {\n"
+" set result \"\"\n"
+" if {[llength $string] >= 2} {\n"
+" lassign $string cmd arg\n"
+" if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
+" catch {\n"
+" set help [$cmd -help $arg]\n"
+" if {[string match \"Usage: $cmd *\" $help]} {\n"
+" set n [llength $string]\n"
+" set subcmd [lindex $help $n]\n"
+" incr n\n"
+" set hint [join [lrange $help $n end]]\n"
+" set prefix \"\"\n"
+" if {![string match \"* \" $string]} {\n"
+" if {$n == 3 && $subcmd ne $arg} {\n"
+"\n"
+" set prefix \"[string range $subcmd [string length $arg] end] \"\n"
+" } else {\n"
+" set prefix \" \"\n"
+" }\n"
+" }\n"
+" set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"_jimsh_init\n"
+);
+}
+int Jim_globInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "glob.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"package require readdir\n"
+"\n"
+"\n"
+"proc glob.globdir {dir pattern} {\n"
+" if {[file exists $dir/$pattern]} {\n"
+"\n"
+" return [list $pattern]\n"
+" }\n"
+"\n"
+" set result {}\n"
+" set files [readdir $dir]\n"
+" lappend files . ..\n"
+"\n"
+" foreach name $files {\n"
+" if {[string match $pattern $name]} {\n"
+"\n"
+" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
+" continue\n"
+" }\n"
+" lappend result $name\n"
+" }\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob.explode {pattern} {\n"
+" set oldexp {}\n"
+" set newexp {\"\"}\n"
+"\n"
+" while 1 {\n"
+" set oldexp $newexp\n"
+" set newexp {}\n"
+" set ob [string first \\{ $pattern]\n"
+" set cb [string first \\} $pattern]\n"
+"\n"
+" if {$ob < $cb && $ob != -1} {\n"
+" set mid [string range $pattern 0 $ob-1]\n"
+" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
+" if {$pattern eq \"\"} {\n"
+" error \"unmatched open brace in glob pattern\"\n"
+" }\n"
+" set pattern [string range $pattern 1 end]\n"
+"\n"
+" foreach subs $subexp {\n"
+" foreach sub [split $subs ,] {\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$mid$sub\n"
+" }\n"
+" }\n"
+" }\n"
+" } elseif {$cb != -1} {\n"
+" set suf [string range $pattern 0 $cb-1]\n"
+" set rest [string range $pattern $cb end]\n"
+" break\n"
+" } else {\n"
+" set suf $pattern\n"
+" set rest \"\"\n"
+" break\n"
+" }\n"
+" }\n"
+"\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$suf\n"
+" }\n"
+" list $rest {*}$newexp\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc glob.glob {base pattern} {\n"
+" set dir [file dirname $pattern]\n"
+" if {$pattern eq $dir || $pattern eq \"\"} {\n"
+" return [list [file join $base $dir] $pattern]\n"
+" } elseif {$pattern eq [file tail $pattern]} {\n"
+" set dir \"\"\n"
+" }\n"
+"\n"
+"\n"
+" set dirlist [glob.glob $base $dir]\n"
+" set pattern [file tail $pattern]\n"
+"\n"
+"\n"
+" set result {}\n"
+" foreach {realdir dir} $dirlist {\n"
+" if {![file isdir $realdir]} {\n"
+" continue\n"
+" }\n"
+" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
+" append dir /\n"
+" }\n"
+" foreach name [glob.globdir $realdir $pattern] {\n"
+" lappend result [file join $realdir $name] $dir$name\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob {args} {\n"
+" set nocomplain 0\n"
+" set base \"\"\n"
+" set tails 0\n"
+"\n"
+" set n 0\n"
+" foreach arg $args {\n"
+" if {[info exists param]} {\n"
+" set $param $arg\n"
+" unset param\n"
+" incr n\n"
+" continue\n"
+" }\n"
+" switch -glob -- $arg {\n"
+" -d* {\n"
+" set switch $arg\n"
+" set param base\n"
+" }\n"
+" -n* {\n"
+" set nocomplain 1\n"
+" }\n"
+" -ta* {\n"
+" set tails 1\n"
+" }\n"
+" -- {\n"
+" incr n\n"
+" break\n"
+" }\n"
+" -* {\n"
+" return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
+" }\n"
+" * {\n"
+" break\n"
+" }\n"
+" }\n"
+" incr n\n"
+" }\n"
+" if {[info exists param]} {\n"
+" return -code error \"missing argument to \\\"$switch\\\"\"\n"
+" }\n"
+" if {[llength $args] <= $n} {\n"
+" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
+" }\n"
+"\n"
+" set args [lrange $args $n end]\n"
+"\n"
+" set result {}\n"
+" foreach pattern $args {\n"
+" set escpattern [string map {\n"
+" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
+" } $pattern]\n"
+" set patexps [lassign [glob.explode $escpattern] rest]\n"
+" if {$rest ne \"\"} {\n"
+" return -code error \"unmatched close brace in glob pattern\"\n"
+" }\n"
+" foreach patexp $patexps {\n"
+" set patexp [string map {\n"
+" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
+" } $patexp]\n"
+" foreach {realname name} [glob.glob $base $patexp] {\n"
+" incr n\n"
+" if {$tails} {\n"
+" lappend result $name\n"
+" } else {\n"
+" lappend result [file join $base $name]\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+" if {!$nocomplain && [llength $result] == 0} {\n"
+" set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
+" return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+);
+}
+int Jim_stdlibInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "stdlib.tcl", 1,
+"\n"
+"\n"
+"if {![exists -command ref]} {\n"
+"\n"
+" proc ref {args} {{count 0}} {\n"
+" format %08x [incr count]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc lambda {arglist args} {\n"
+" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
+"}\n"
+"\n"
+"proc lambda.finalizer {name val} {\n"
+" rename $name {}\n"
+"}\n"
+"\n"
+"\n"
+"proc curry {args} {\n"
+" alias [ref {} function lambda.finalizer] {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc function {value} {\n"
+" return $value\n"
+"}\n"
+"\n"
+"\n"
+"proc stackdump {stacktrace} {\n"
+" set lines {}\n"
+" lappend lines \"Traceback (most recent call last):\"\n"
+" foreach {cmd l f p} [lreverse $stacktrace] {\n"
+" set line {}\n"
+" if {$f ne \"\"} {\n"
+" append line \" File \\\"$f\\\", line $l\"\n"
+" }\n"
+" if {$p ne \"\"} {\n"
+" append line \", in $p\"\n"
+" }\n"
+" if {$line ne \"\"} {\n"
+" lappend lines $line\n"
+" if {$cmd ne \"\"} {\n"
+" set nl [string first \\n $cmd 1]\n"
+" if {$nl >= 0} {\n"
+" set cmd [string range $cmd 0 $nl-1]...\n"
+" }\n"
+" lappend lines \" $cmd\"\n"
+" }\n"
+" }\n"
+" }\n"
+" if {[llength $lines] > 1} {\n"
+" return [join $lines \\n]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc defer {script} {\n"
+" upvar jim::defer v\n"
+" lappend v $script\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc errorInfo {msg {stacktrace \"\"}} {\n"
+" if {$stacktrace eq \"\"} {\n"
+"\n"
+" set stacktrace [info stacktrace]\n"
+" }\n"
+" lassign $stacktrace p f l cmd\n"
+" if {$f ne \"\"} {\n"
+" set result \"$f:$l: Error: \"\n"
+" }\n"
+" append result \"$msg\\n\"\n"
+" append result [stackdump $stacktrace]\n"
+"\n"
+"\n"
+" string trim $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc {info nameofexecutable} {} {\n"
+" if {[exists ::jim::exe]} {\n"
+" return $::jim::exe\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict update} {&varName args script} {\n"
+" set keys {}\n"
+" foreach {n v} $args {\n"
+" upvar $v var_$v\n"
+" if {[dict exists $varName $n]} {\n"
+" set var_$v [dict get $varName $n]\n"
+" }\n"
+" }\n"
+" catch {uplevel 1 $script} msg opts\n"
+" if {[info exists varName]} {\n"
+" foreach {n v} $args {\n"
+" if {[info exists var_$v]} {\n"
+" dict set varName $n [set var_$v]\n"
+" } else {\n"
+" dict unset varName $n\n"
+" }\n"
+" }\n"
+" }\n"
+" return {*}$opts $msg\n"
+"}\n"
+"\n"
+"proc {dict replace} {dictionary {args {key value}}} {\n"
+" if {[llength ${key value}] % 2} {\n"
+" tailcall {dict replace}\n"
+" }\n"
+" tailcall dict merge $dictionary ${key value}\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict lappend} {varName key {args value}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set list [dict get $dict $key]\n"
+" }\n"
+" lappend list {*}$value\n"
+" dict set dict $key $list\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict append} {varName key {args value}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set str [dict get $dict $key]\n"
+" }\n"
+" append str {*}$value\n"
+" dict set dict $key $str\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict incr} {varName key {increment 1}} {\n"
+" upvar $varName dict\n"
+" if {[exists dict] && [dict exists $dict $key]} {\n"
+" set value [dict get $dict $key]\n"
+" }\n"
+" incr value $increment\n"
+" dict set dict $key $value\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict remove} {dictionary {args key}} {\n"
+" foreach k $key {\n"
+" dict unset dictionary $k\n"
+" }\n"
+" return $dictionary\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict for} {vars dictionary script} {\n"
+" if {[llength $vars] != 2} {\n"
+" return -code error \"must have exactly two variable names\"\n"
+" }\n"
+" dict size $dictionary\n"
+" tailcall foreach $vars $dictionary $script\n"
+"}\n"
+);
+}
+int Jim_tclcompatInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "tclcompat.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"set env [env]\n"
+"\n"
+"\n"
+"if {[exists -command stdout]} {\n"
+"\n"
+" foreach p {gets flush close eof seek tell} {\n"
+" proc $p {chan args} {p} {\n"
+" tailcall $chan $p {*}$args\n"
+" }\n"
+" }\n"
+" unset p\n"
+"\n"
+"\n"
+"\n"
+" proc puts {{-nonewline {}} {chan stdout} msg} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} puts $msg\n"
+" }\n"
+" tailcall $chan puts {*}${-nonewline} $msg\n"
+" }\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+" proc read {{-nonewline {}} chan} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} read {*}${chan}\n"
+" }\n"
+" tailcall $chan read {*}${-nonewline}\n"
+" }\n"
+"\n"
+" proc fconfigure {f args} {\n"
+" foreach {n v} $args {\n"
+" switch -glob -- $n {\n"
+" -bl* {\n"
+" $f ndelay $(!$v)\n"
+" }\n"
+" -bu* {\n"
+" $f buffering $v\n"
+" }\n"
+" -tr* {\n"
+" $f translation $v\n"
+" }\n"
+" default {\n"
+" return -code error \"fconfigure: unknown option $n\"\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc fileevent {args} {\n"
+" tailcall {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc parray {arrayname {pattern *} {puts puts}} {\n"
+" upvar $arrayname a\n"
+"\n"
+" set max 0\n"
+" foreach name [array names a $pattern]] {\n"
+" if {[string length $name] > $max} {\n"
+" set max [string length $name]\n"
+" }\n"
+" }\n"
+" incr max [string length $arrayname]\n"
+" incr max 2\n"
+" foreach name [lsort [array names a $pattern]] {\n"
+" $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc {file copy} {{force {}} source target} {\n"
+" try {\n"
+" if {$force ni {{} -force}} {\n"
+" error \"bad option \\\"$force\\\": should be -force\"\n"
+" }\n"
+"\n"
+" set in [open $source rb]\n"
+"\n"
+" if {[file exists $target]} {\n"
+" if {$force eq \"\"} {\n"
+" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
+" }\n"
+"\n"
+" if {$source eq $target} {\n"
+" return\n"
+" }\n"
+"\n"
+"\n"
+" file stat $source ss\n"
+" file stat $target ts\n"
+" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
+" return\n"
+" }\n"
+" }\n"
+" set out [open $target wb]\n"
+" $in copyto $out\n"
+" $out close\n"
+" } on error {msg opts} {\n"
+" incr opts(-level)\n"
+" return {*}$opts $msg\n"
+" } finally {\n"
+" catch {$in close}\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc popen {cmd {mode r}} {\n"
+" lassign [pipe] r w\n"
+" try {\n"
+" if {[string match \"w*\" $mode]} {\n"
+" lappend cmd <@$r &\n"
+" set pids [exec {*}$cmd]\n"
+" $r close\n"
+" set f $w\n"
+" } else {\n"
+" lappend cmd >@$w &\n"
+" set pids [exec {*}$cmd]\n"
+" $w close\n"
+" set f $r\n"
+" }\n"
+" lambda {cmd args} {f pids} {\n"
+" if {$cmd eq \"pid\"} {\n"
+" return $pids\n"
+" }\n"
+" if {$cmd eq \"close\"} {\n"
+" $f close\n"
+"\n"
+" set retopts {}\n"
+" foreach p $pids {\n"
+" lassign [wait $p] status - rc\n"
+" if {$status eq \"CHILDSTATUS\"} {\n"
+" if {$rc == 0} {\n"
+" continue\n"
+" }\n"
+" set msg \"child process exited abnormally\"\n"
+" } else {\n"
+" set msg \"child killed: received signal\"\n"
+" }\n"
+" set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
+" }\n"
+" return {*}$retopts\n"
+" }\n"
+" tailcall $f $cmd {*}$args\n"
+" }\n"
+" } on error {error opts} {\n"
+" $r close\n"
+" $w close\n"
+" error $error\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"local proc pid {{channelId {}}} {\n"
+" if {$channelId eq \"\"} {\n"
+" tailcall upcall pid\n"
+" }\n"
+" if {[catch {$channelId tell}]} {\n"
+" return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
+" }\n"
+" if {[catch {$channelId pid} pids]} {\n"
+" return \"\"\n"
+" }\n"
+" return $pids\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc throw {code {msg \"\"}} {\n"
+" return -code $code $msg\n"
+"}\n"
+"\n"
+"\n"
+"proc {file delete force} {path} {\n"
+" foreach e [readdir $path] {\n"
+" file delete -force $path/$e\n"
+" }\n"
+" file delete $path\n"
+"}\n"
+);
+}
+
+
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_UNISTD_H
+#include
+#include
+#endif
+#ifdef HAVE_UTIL_H
+#include
+#endif
+#ifdef HAVE_PTY_H
+#include
+#endif
+
+
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_SYS_UN_H
+#include
+#endif
+#define HAVE_SOCKETS
+#elif defined (__MINGW32__)
+
+#endif
+
+#if defined(JIM_SSL)
+#include
+#include
+#endif
+
+#ifdef HAVE_TERMIOS_H
+#endif
+
+
+#define AIO_CMD_LEN 32
+#define AIO_DEFAULT_RBUF_LEN 256
+#define AIO_DEFAULT_WBUF_LIMIT (64 * 1024)
+
+#define AIO_KEEPOPEN 1
+#define AIO_NODELETE 2
+#define AIO_EOF 4
+#define AIO_WBUF_NONE 8
+#define AIO_NONBLOCK 16
+
+#define AIO_ONEREAD 32
+
+enum wbuftype {
+ WBUF_OPT_NONE,
+ WBUF_OPT_LINE,
+ WBUF_OPT_FULL,
+};
+
+#if defined(JIM_IPV6)
+#define IPV6 1
+#else
+#define IPV6 0
+#ifndef PF_INET6
+#define PF_INET6 0
+#endif
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
+#define UNIX_SOCKETS 1
+#else
+#define UNIX_SOCKETS 0
+#endif
+
+
+
+
+static int JimReadableTimeout(int fd, long ms)
+{
+#ifdef HAVE_SELECT
+ int retval;
+ struct timeval tv;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+
+ FD_SET(fd, &rfds);
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000;
+
+ retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
+
+ if (retval > 0) {
+ return JIM_OK;
+ }
+ return JIM_ERR;
+#else
+ return JIM_OK;
+#endif
+}
+
+
+struct AioFile;
+
+typedef struct {
+ int (*writer)(struct AioFile *af, const char *buf, int len);
+ int (*reader)(struct AioFile *af, char *buf, int len, int pending);
+ int (*error)(const struct AioFile *af);
+ const char *(*strerror)(struct AioFile *af);
+ int (*verify)(struct AioFile *af);
+} JimAioFopsType;
+
+typedef struct AioFile
+{
+ Jim_Obj *filename;
+ int wbuft;
+ int flags;
+ long timeout;
+ int fd;
+ int addr_family;
+ void *ssl;
+ const JimAioFopsType *fops;
+ Jim_Obj *readbuf;
+ Jim_Obj *writebuf;
+ char *rbuf;
+ size_t rbuf_len;
+ size_t wbuf_limit;
+} AioFile;
+
+static void aio_consume(Jim_Obj *objPtr, int n);
+
+static int stdio_writer(struct AioFile *af, const char *buf, int len)
+{
+ int ret = write(af->fd, buf, len);
+ if (ret < 0 && errno == EPIPE) {
+ aio_consume(af->writebuf, Jim_Length(af->writebuf));
+ }
+ return ret;
+}
+
+static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
+{
+ if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {
+
+ int ret;
+
+ errno = 0;
+ ret = read(af->fd, buf, len);
+ if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
+ af->flags |= AIO_EOF;
+ }
+ return ret;
+ }
+ errno = ETIMEDOUT;
+ return -1;
+}
+
+static int stdio_error(const AioFile *af)
+{
+ if (af->flags & AIO_EOF) {
+ return JIM_OK;
+ }
+
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ case ETIMEDOUT:
+#ifdef ECONNRESET
+ case ECONNRESET:
+#endif
+#ifdef ECONNABORTED
+ case ECONNABORTED:
+#endif
+ return JIM_OK;
+ default:
+ return JIM_ERR;
+ }
+}
+
+static const char *stdio_strerror(struct AioFile *af)
+{
+ return strerror(errno);
+}
+
+static const JimAioFopsType stdio_fops = {
+ stdio_writer,
+ stdio_reader,
+ stdio_error,
+ stdio_strerror,
+ NULL,
+};
+
+
+static void aio_set_nonblocking(AioFile *af, int nb)
+{
+#ifdef O_NDELAY
+ int old = !!(af->flags & AIO_NONBLOCK);
+ if (old != nb) {
+ int fmode = fcntl(af->fd, F_GETFL);
+ if (nb) {
+ fmode |= O_NDELAY;
+ af->flags |= AIO_NONBLOCK;
+ }
+ else {
+ fmode &= ~O_NDELAY;
+ af->flags &= ~AIO_NONBLOCK;
+ }
+ (void)fcntl(af->fd, F_SETFL, fmode);
+ }
+#endif
+}
+
+static int aio_start_nonblocking(AioFile *af)
+{
+ int old = !!(af->flags & AIO_NONBLOCK);
+ if (af->timeout) {
+ aio_set_nonblocking(af, 1);
+ }
+ return old;
+}
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags);
+
+
+static const char *JimAioErrorString(AioFile *af)
+{
+ if (af && af->fops)
+ return af->fops->strerror(af);
+
+ return strerror(errno);
+}
+
+static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (name) {
+ Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af));
+ }
+ else {
+ Jim_SetResultString(interp, JimAioErrorString(af), -1);
+ }
+}
+
+static int aio_eof(AioFile *af)
+{
+ return af->flags & AIO_EOF;
+}
+
+static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
+{
+ int ret = 0;
+ if (!aio_eof(af)) {
+ ret = af->fops->error(af);
+ if (ret) {
+ JimAioSetError(interp, af->filename);
+ }
+ }
+ return ret;
+}
+
+static void aio_consume(Jim_Obj *objPtr, int n)
+{
+ assert(objPtr->bytes);
+ assert(n <= objPtr->length);
+
+
+ memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
+ objPtr->length -= n;
+}
+
+
+static int aio_flush(Jim_Interp *interp, AioFile *af);
+
+#ifdef jim_ext_eventloop
+static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
+{
+ AioFile *af = clientData;
+
+ aio_flush(interp, af);
+ if (Jim_Length(af->writebuf) == 0) {
+
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+
+static int aio_flush(Jim_Interp *interp, AioFile *af)
+{
+ int len;
+ const char *pt = Jim_GetString(af->writebuf, &len);
+ if (len) {
+ int ret = af->fops->writer(af, pt, len);
+ if (ret > 0) {
+
+ aio_consume(af->writebuf, ret);
+ }
+ if (ret < 0) {
+ return JimCheckStreamError(interp, af);
+ }
+ if (Jim_Length(af->writebuf)) {
+#ifdef jim_ext_eventloop
+ void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
+ if (handler == NULL) {
+ Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
+ return JIM_OK;
+ }
+ else if (handler == af) {
+
+ return JIM_OK;
+ }
+#endif
+
+ Jim_SetResultString(interp, "send buffer is full", -1);
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
+{
+ if (!af->readbuf) {
+ af->readbuf = Jim_NewStringObj(interp, NULL, 0);
+ }
+
+ if (neededLen >= 0) {
+ neededLen -= Jim_Length(af->readbuf);
+ if (neededLen <= 0) {
+ return JIM_OK;
+ }
+ }
+
+ while (neededLen && !aio_eof(af)) {
+ int retval;
+ int readlen;
+
+ if (neededLen == -1) {
+ readlen = af->rbuf_len;
+ }
+ else {
+ readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
+ }
+
+ if (!af->rbuf) {
+ af->rbuf = Jim_Alloc(af->rbuf_len);
+ }
+ retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
+ if (retval > 0) {
+ if (retval) {
+ Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
+ }
+ if (neededLen != -1) {
+ neededLen -= retval;
+ }
+ if (flags & AIO_ONEREAD) {
+ return JIM_OK;
+ }
+ continue;
+ }
+ if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
+ return JIM_ERR;
+ }
+ break;
+ }
+
+ return JIM_OK;
+}
+
+static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
+{
+ Jim_Obj *objPtr = NULL;
+
+ if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
+ objPtr = af->readbuf;
+ af->readbuf = NULL;
+ }
+ else if (af->readbuf) {
+
+ int len;
+ const char *pt = Jim_GetString(af->readbuf, &len);
+
+ objPtr = Jim_NewStringObj(interp, pt, neededLen);
+ aio_consume(af->readbuf, neededLen);
+ }
+
+ return objPtr;
+}
+
+static void JimAioDelProc(Jim_Interp *interp, void *privData)
+{
+ AioFile *af = privData;
+
+ JIM_NOTUSED(interp);
+
+
+ aio_flush(interp, af);
+ Jim_DecrRefCount(interp, af->writebuf);
+
+#if UNIX_SOCKETS
+ if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
+
+ Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
+ if (filenameObj) {
+ if (Jim_Length(filenameObj)) {
+ remove(Jim_String(filenameObj));
+ }
+ Jim_FreeNewObj(interp, filenameObj);
+ }
+ }
+#endif
+
+ Jim_DecrRefCount(interp, af->filename);
+
+#ifdef jim_ext_eventloop
+
+ Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
+#endif
+
+#if defined(JIM_SSL)
+ if (af->ssl != NULL) {
+ SSL_free(af->ssl);
+ }
+#endif
+ if (!(af->flags & AIO_KEEPOPEN)) {
+ close(af->fd);
+ }
+ if (af->readbuf) {
+ Jim_FreeNewObj(interp, af->readbuf);
+ }
+
+ Jim_Free(af->rbuf);
+ Jim_Free(af);
+}
+
+static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int nonewline = 0;
+ jim_wide neededLen = -1;
+ static const char * const options[] = { "-pending", "-nonewline", NULL };
+ enum { OPT_PENDING, OPT_NONEWLINE };
+ int option;
+ int nb;
+ Jim_Obj *objPtr;
+
+ if (argc) {
+ if (*Jim_String(argv[0]) == '-') {
+ if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_PENDING:
+
+ break;
+ case OPT_NONEWLINE:
+ nonewline++;
+ break;
+ }
+ }
+ else {
+ if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
+ return JIM_ERR;
+ if (neededLen < 0) {
+ Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+ return JIM_ERR;
+ }
+ }
+ argc--;
+ argv++;
+ }
+ if (argc) {
+ return -1;
+ }
+
+
+ nb = aio_start_nonblocking(af);
+
+ if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
+ aio_set_nonblocking(af, nb);
+ return JIM_ERR;
+ }
+ objPtr = aio_read_consume(interp, af, neededLen);
+
+ aio_set_nonblocking(af, nb);
+
+ if (objPtr) {
+ if (nonewline) {
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ else {
+ Jim_SetEmptyResult(interp);
+ }
+ return JIM_OK;
+}
+
+int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+{
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
+
+ if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+ return ((AioFile *) cmdPtr->u.native.privData)->fd;
+ }
+ Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+ return -1;
+}
+
+static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+
+ aio_flush(interp, af);
+
+ Jim_SetResultInt(interp, af->fd);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ jim_wide count = 0;
+ jim_wide maxlen = JIM_WIDE_MAX;
+ int ok = 1;
+ Jim_Obj *objv[4];
+
+ if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ objv[0] = argv[0];
+ objv[1] = Jim_NewStringObj(interp, "flush", -1);
+ if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
+ return JIM_ERR;
+ }
+
+
+ objv[0] = argv[0];
+ objv[1] = Jim_NewStringObj(interp, "puts", -1);
+ objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
+ Jim_IncrRefCount(objv[1]);
+ Jim_IncrRefCount(objv[2]);
+
+ while (count < maxlen) {
+ jim_wide len = maxlen - count;
+ if (len > af->rbuf_len) {
+ len = af->rbuf_len;
+ }
+ if (aio_read_len(interp, af, 0, len) != JIM_OK) {
+ ok = 0;
+ break;
+ }
+ objv[3] = aio_read_consume(interp, af, len);
+ count += Jim_Length(objv[3]);
+ if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
+ ok = 0;
+ break;
+ }
+ if (aio_eof(af)) {
+ break;
+ }
+ if (count >= 16384 && af->rbuf_len < 65536) {
+
+ af->rbuf_len = 65536;
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
+ }
+
+ Jim_DecrRefCount(interp, objv[1]);
+ Jim_DecrRefCount(interp, objv[2]);
+
+ if (!ok) {
+ return JIM_ERR;
+ }
+
+ Jim_SetResultInt(interp, count);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *objPtr = NULL;
+ int len;
+ int nb;
+ unsigned flags = AIO_ONEREAD;
+ char *nl = NULL;
+ int offset = 0;
+
+ errno = 0;
+
+
+ nb = aio_start_nonblocking(af);
+ if (nb) {
+ flags |= AIO_NONBLOCK;
+ }
+
+ while (!aio_eof(af)) {
+ if (af->readbuf) {
+ const char *pt = Jim_GetString(af->readbuf, &len);
+ nl = memchr(pt + offset, '\n', len - offset);
+ if (nl) {
+
+ objPtr = Jim_NewStringObj(interp, pt, nl - pt);
+
+ aio_consume(af->readbuf, nl - pt + 1);
+ break;
+ }
+ offset = len;
+ }
+
+
+ if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
+ break;
+ }
+ }
+
+ aio_set_nonblocking(af, nb);
+
+ if (!nl && aio_eof(af) && af->readbuf) {
+
+ objPtr = af->readbuf;
+ af->readbuf = NULL;
+ }
+ else if (!objPtr) {
+ objPtr = Jim_NewStringObj(interp, NULL, 0);
+ }
+
+ if (argc) {
+ if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ return JIM_ERR;
+ }
+
+ len = Jim_Length(objPtr);
+
+ if (!nl && len == 0) {
+
+ len = -1;
+ }
+ Jim_SetResultInt(interp, len);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int wlen;
+ const char *wdata;
+ Jim_Obj *strObj;
+ int wnow = 0;
+ int nl = 1;
+
+ if (argc == 2) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+ return -1;
+ }
+ strObj = argv[1];
+ nl = 0;
+ }
+ else {
+ strObj = argv[0];
+ }
+
+#ifdef JIM_MAINTAINER
+ if (Jim_IsShared(af->writebuf)) {
+ Jim_DecrRefCount(interp, af->writebuf);
+ af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
+ Jim_IncrRefCount(af->writebuf);
+ }
+#endif
+ Jim_AppendObj(interp, af->writebuf, strObj);
+ if (nl) {
+ Jim_AppendString(interp, af->writebuf, "\n", 1);
+ }
+
+
+ wdata = Jim_GetString(af->writebuf, &wlen);
+ switch (af->wbuft) {
+ case WBUF_OPT_NONE:
+
+ wnow = 1;
+ break;
+
+ case WBUF_OPT_LINE:
+
+ if (nl || memchr(wdata, '\n', wlen) != NULL) {
+ wnow = 1;
+ }
+ break;
+
+ case WBUF_OPT_FULL:
+ if (wlen >= af->wbuf_limit) {
+ wnow = 1;
+ }
+ break;
+ }
+
+ if (wnow) {
+ return aio_flush(interp, af);
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_ISATTY
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetResultInt(interp, isatty(af->fd));
+#else
+ Jim_SetResultInt(interp, 0);
+#endif
+
+ return JIM_OK;
+}
+
+
+static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ return aio_flush(interp, af);
+}
+
+static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, !!aio_eof(af));
+ return JIM_OK;
+}
+
+static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ if (argc == 3) {
+ int option = -1;
+#if defined(HAVE_SOCKETS)
+ static const char * const options[] = { "r", "w", "-nodelete", NULL };
+ enum { OPT_R, OPT_W, OPT_NODELETE };
+
+ if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#endif
+ switch (option) {
+#if defined(HAVE_SHUTDOWN)
+ case OPT_R:
+ case OPT_W:
+ if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
+ return JIM_OK;
+ }
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+#endif
+#if UNIX_SOCKETS
+ case OPT_NODELETE:
+ if (af->addr_family == PF_UNIX) {
+ af->flags |= AIO_NODELETE;
+ break;
+ }
+
+#endif
+ default:
+ Jim_SetResultString(interp, "not supported", -1);
+ return JIM_ERR;
+ }
+ }
+
+
+ af->flags &= ~AIO_KEEPOPEN;
+
+ return Jim_DeleteCommand(interp, argv[0]);
+}
+
+static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int orig = SEEK_SET;
+ jim_wide offset;
+
+ if (argc == 2) {
+ if (Jim_CompareStringImmediate(interp, argv[1], "start"))
+ orig = SEEK_SET;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
+ orig = SEEK_CUR;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
+ orig = SEEK_END;
+ else {
+ return -1;
+ }
+ }
+ if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (orig != SEEK_CUR || offset != 0) {
+
+ aio_flush(interp, af);
+ }
+ if (Jim_Lseek(af->fd, offset, orig) == -1) {
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+ }
+ if (af->readbuf) {
+ Jim_FreeNewObj(interp, af->readbuf);
+ af->readbuf = NULL;
+ }
+ af->flags &= ~AIO_EOF;
+ return JIM_OK;
+}
+
+static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
+ return JIM_OK;
+}
+
+static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResult(interp, af->filename);
+ return JIM_OK;
+}
+
+#ifdef O_NDELAY
+static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long nb;
+
+ if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ aio_set_nonblocking(af, nb);
+ }
+ Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
+ return JIM_OK;
+}
+#endif
+
+
+#ifdef HAVE_FSYNC
+static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ fsync(af->fd);
+ return JIM_OK;
+}
+#endif
+
+static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_Obj *resultObj;
+
+ static const char * const options[] = {
+ "none",
+ "line",
+ "full",
+ NULL
+ };
+
+ if (argc) {
+ if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
+ long l;
+ if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->wbuf_limit = l;
+ }
+
+ if (af->wbuft == WBUF_OPT_NONE) {
+ if (aio_flush(interp, af) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ }
+
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
+ if (af->wbuft == WBUF_OPT_FULL) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
+ }
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum {OPT_BINARY, OPT_TEXT};
+ static const char * const options[] = {
+ "binary",
+ "text",
+ NULL
+ };
+ int opt;
+
+ if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+#if defined(Jim_SetMode)
+ else {
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT);
+ }
+#endif
+ return JIM_OK;
+}
+
+static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (argc) {
+ long l;
+ if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
+ return JIM_ERR;
+ }
+ af->rbuf_len = l;
+ if (af->rbuf) {
+ af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
+ }
+ }
+ Jim_SetResultInt(interp, af->rbuf_len);
+
+ return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
+static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_SELECT
+ AioFile *af = Jim_CmdPrivData(interp);
+ if (argc == 1) {
+ if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ Jim_SetResultInt(interp, af->timeout);
+ return JIM_OK;
+#else
+ Jim_SetResultString(interp, "timeout not supported", -1);
+ return JIM_ERR;
+#endif
+}
+
+static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
+ int argc, Jim_Obj * const *argv)
+{
+ if (argc == 0) {
+
+ Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+ }
+
+
+ Jim_DeleteFileHandler(interp, af->fd, mask);
+
+
+ if (Jim_Length(argv[0])) {
+ Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
+ }
+
+ return JIM_OK;
+}
+
+static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
+}
+
+static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
+}
+
+static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
+}
+#endif
+
+#if defined(jim_ext_file) && defined(Jim_FileStat)
+static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (Jim_FileStat(af->fd, &sb) == -1) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
+}
+#endif
+
+
+
+
+static const jim_subcmd_type aio_command_table[] = {
+ { "read",
+ "?-nonewline|len?",
+ aio_cmd_read,
+ 0,
+ 2,
+
+ },
+ { "copyto",
+ "handle ?size?",
+ aio_cmd_copy,
+ 1,
+ 2,
+
+ },
+ { "getfd",
+ NULL,
+ aio_cmd_getfd,
+ 0,
+ 0,
+
+ },
+ { "gets",
+ "?var?",
+ aio_cmd_gets,
+ 0,
+ 1,
+
+ },
+ { "puts",
+ "?-nonewline? str",
+ aio_cmd_puts,
+ 1,
+ 2,
+
+ },
+ { "isatty",
+ NULL,
+ aio_cmd_isatty,
+ 0,
+ 0,
+
+ },
+ { "flush",
+ NULL,
+ aio_cmd_flush,
+ 0,
+ 0,
+
+ },
+ { "eof",
+ NULL,
+ aio_cmd_eof,
+ 0,
+ 0,
+
+ },
+ { "close",
+ "?r(ead)|w(rite)?",
+ aio_cmd_close,
+ 0,
+ 1,
+ JIM_MODFLAG_FULLARGV,
+
+ },
+ { "seek",
+ "offset ?start|current|end",
+ aio_cmd_seek,
+ 1,
+ 2,
+
+ },
+ { "tell",
+ NULL,
+ aio_cmd_tell,
+ 0,
+ 0,
+
+ },
+ { "filename",
+ NULL,
+ aio_cmd_filename,
+ 0,
+ 0,
+
+ },
+#ifdef O_NDELAY
+ { "ndelay",
+ "?0|1?",
+ aio_cmd_ndelay,
+ 0,
+ 1,
+
+ },
+#endif
+#ifdef HAVE_FSYNC
+ { "sync",
+ NULL,
+ aio_cmd_sync,
+ 0,
+ 0,
+
+ },
+#endif
+ { "buffering",
+ "?none|line|full? ?size?",
+ aio_cmd_buffering,
+ 0,
+ 2,
+
+ },
+ { "translation",
+ "binary|text",
+ aio_cmd_translation,
+ 1,
+ 1,
+
+ },
+ { "readsize",
+ "?size?",
+ aio_cmd_readsize,
+ 0,
+ 1,
+
+ },
+#if defined(jim_ext_file) && defined(Jim_FileStat)
+ { "stat",
+ "?var?",
+ aio_cmd_stat,
+ 0,
+ 1,
+
+ },
+#endif
+#ifdef jim_ext_eventloop
+ { "readable",
+ "?readable-script?",
+ aio_cmd_readable,
+ 0,
+ 1,
+
+ },
+ { "writable",
+ "?writable-script?",
+ aio_cmd_writable,
+ 0,
+ 1,
+
+ },
+ { "onexception",
+ "?exception-script?",
+ aio_cmd_onexception,
+ 0,
+ 1,
+
+ },
+ { "timeout",
+ "?ms?",
+ aio_cmd_timeout,
+ 0,
+ 1,
+
+ },
+#endif
+ { NULL }
+};
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
+}
+
+static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
+{
+ int i;
+ int flags = 0;
+ #ifndef O_NOCTTY
+
+ #define O_NOCTTY 0
+ #endif
+ static const char * const modetypes[] = {
+ "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
+ };
+ static const int modeflags[] = {
+ O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
+ };
+
+ for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
+ int opt;
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
+ if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
+ return -1;
+ }
+ flags |= modeflags[opt];
+ }
+ return flags;
+}
+
+static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
+{
+
+ int flags;
+ const char *mode = Jim_String(modeObj);
+ if (*mode == 'R' || *mode == 'W') {
+ return parse_posix_open_mode(interp, modeObj);
+ }
+ if (*mode == 'r') {
+ flags = O_RDONLY;
+ }
+ else if (*mode == 'w') {
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ }
+ else if (*mode == 'a') {
+ flags = O_WRONLY | O_CREAT | O_APPEND;
+ }
+ else {
+ Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
+ return -1;
+ }
+ mode++;
+
+ if (*mode == 'b') {
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+ mode++;
+ }
+
+ if (*mode == 't') {
+#ifdef O_TEXT
+ flags |= O_TEXT;
+#endif
+ mode++;
+ }
+
+ if (*mode == '+') {
+ mode++;
+
+ flags &= ~(O_RDONLY | O_WRONLY);
+ flags |= O_RDWR;
+ }
+
+ if (*mode == 'x') {
+ mode++;
+#ifdef O_EXCL
+ flags |= O_EXCL;
+#endif
+ }
+
+ if (*mode == 'F') {
+ mode++;
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+ }
+
+ if (*mode == 'e') {
+
+ mode++;
+ }
+ return flags;
+}
+
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv)
+{
+ int openflags;
+ const char *filename;
+ int fd = -1;
+ int n = 0;
+ int flags = 0;
+
+ if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
+ flags = AIO_KEEPOPEN;
+ n++;
+ }
+ if (argc < 2 || argc > 3 + n) {
+ Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
+ return JIM_ERR;
+ }
+
+ filename = Jim_String(argv[1]);
+
+#ifdef jim_ext_tclcompat
+ {
+
+
+ if (*filename == '|') {
+ Jim_Obj *evalObj[3];
+ int i = 0;
+
+ evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
+ evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
+ if (argc == 3 + n) {
+ evalObj[i++] = argv[2 + n];
+ }
+
+ return Jim_EvalObjVector(interp, i, evalObj);
+ }
+ }
+#endif
+ if (argc == 3 + n) {
+ openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
+ if (openflags == -1) {
+ return JIM_ERR;
+ }
+ }
+ else {
+ openflags = O_RDONLY;
+ }
+ fd = open(filename, openflags, 0666);
+ if (fd < 0) {
+ JimAioSetError(interp, argv[1]);
+ return JIM_ERR;
+ }
+
+ return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
+}
+
+
+static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags)
+{
+ AioFile *af;
+ char buf[AIO_CMD_LEN];
+ Jim_Obj *cmdname;
+
+ snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+ cmdname = Jim_NewStringObj(interp, buf, -1);
+ if (!filename) {
+ filename = cmdname;
+ }
+ Jim_IncrRefCount(filename);
+
+
+ af = Jim_Alloc(sizeof(*af));
+ memset(af, 0, sizeof(*af));
+ af->filename = filename;
+ af->fd = fd;
+ af->addr_family = family;
+ af->fops = &stdio_fops;
+ af->ssl = NULL;
+ if (flags & AIO_WBUF_NONE) {
+ af->wbuft = WBUF_OPT_NONE;
+ }
+ else {
+#ifdef HAVE_ISATTY
+ af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
+#else
+ af->wbuft = WBUF_OPT_FULL;
+#endif
+ }
+
+#ifdef FD_CLOEXEC
+ if ((flags & AIO_KEEPOPEN) == 0) {
+ (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
+ }
+#endif
+ aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
+
+ af->flags |= flags;
+
+ af->writebuf = Jim_NewStringObj(interp, NULL, 0);
+ Jim_IncrRefCount(af->writebuf);
+ af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
+ af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
+
+
+ Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
+
+ Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));
+
+ return af;
+}
+
+#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
+static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
+ const char *hdlfmt, int family, int flags)
+{
+ if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
+ Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+ if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
+ Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+
+
+ close(p[0]);
+ close(p[1]);
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+}
+#endif
+
+#ifdef HAVE_PIPE
+static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
+{
+ int p[2];
+
+ if (pipe(p) != 0) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+
+ return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
+}
+
+
+static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+ return JimCreatePipe(interp, argv[0], 0);
+}
+#endif
+
+#ifdef HAVE_OPENPTY
+static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int p[2];
+ char path[MAXPATHLEN];
+
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+
+ if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
+ JimAioSetError(interp, NULL);
+ return JIM_ERR;
+ }
+
+
+ return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
+ return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
+}
+#endif
+
+
+
+int Jim_aioInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+#if defined(JIM_SSL)
+ Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
+#endif
+
+ Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
+#ifdef HAVE_SOCKETS
+ Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
+#endif
+#ifdef HAVE_PIPE
+ Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
+#endif
+
+
+ JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
+ JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
+ JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);
+
+ return JIM_OK;
+}
+
+#include
+#include
+#include
+
+
+#ifdef HAVE_DIRENT_H
+#include
+#endif
+
+int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *dirPath;
+ DIR *dirPtr;
+ struct dirent *entryPtr;
+ int nocomplain = 0;
+
+ if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
+ nocomplain = 1;
+ }
+ if (argc != 2 && !nocomplain) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
+ return JIM_ERR;
+ }
+
+ dirPath = Jim_String(argv[1 + nocomplain]);
+
+ dirPtr = opendir(dirPath);
+ if (dirPtr == NULL) {
+ if (nocomplain) {
+ return JIM_OK;
+ }
+ Jim_SetResultString(interp, strerror(errno), -1);
+ return JIM_ERR;
+ }
+ else {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ while ((entryPtr = readdir(dirPtr)) != NULL) {
+ if (entryPtr->d_name[0] == '.') {
+ if (entryPtr->d_name[1] == '\0') {
+ continue;
+ }
+ if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
+ continue;
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
+ }
+ closedir(dirPtr);
+
+ Jim_SetResult(interp, listObj);
+
+ return JIM_OK;
+ }
+}
+
+int Jim_readdirInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "readdir");
+ Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+
+#if defined(JIM_REGEXP)
+#else
+ #include
+ #define jim_regcomp regcomp
+ #define jim_regexec regexec
+ #define jim_regerror regerror
+ #define jim_regfree regfree
+#endif
+
+static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
+ Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
+}
+
+static const Jim_ObjType regexpObjType = {
+ "regexp",
+ FreeRegexpInternalRep,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE
+};
+
+static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
+{
+ regex_t *compre;
+ const char *pattern;
+ int ret;
+
+
+ if (objPtr->typePtr == ®expObjType &&
+ objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
+
+ return objPtr->internalRep.ptrIntValue.ptr;
+ }
+
+
+
+
+ pattern = Jim_String(objPtr);
+ compre = Jim_Alloc(sizeof(regex_t));
+
+ if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+ char buf[100];
+
+ jim_regerror(ret, compre, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
+ jim_regfree(compre);
+ Jim_Free(compre);
+ return NULL;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = ®expObjType;
+ objPtr->internalRep.ptrIntValue.int1 = flags;
+ objPtr->internalRep.ptrIntValue.ptr = compre;
+
+ return compre;
+}
+
+int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int opt_indices = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ regex_t *regex;
+ int match, i, j;
+ int offset = 0;
+ regmatch_t *pmatch = NULL;
+ int source_len;
+ int result = JIM_OK;
+ const char *pattern;
+ const char *source_str;
+ int num_matches = 0;
+ int num_vars;
+ Jim_Obj *resultListObj = NULL;
+ int regcomp_flags = 0;
+ int eflags = 0;
+ int option;
+ enum {
+ OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
+ };
+ static const char * const options[] = {
+ "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
+ };
+
+ if (argc < 3) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_INDICES:
+ opt_indices = 1;
+ break;
+
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_INLINE:
+ opt_inline = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+ if (argc - i < 2) {
+ goto wrongNumArgs;
+ }
+
+ regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+ if (!regex) {
+ return JIM_ERR;
+ }
+
+ pattern = Jim_String(argv[i]);
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+
+ num_vars = argc - i - 2;
+
+ if (opt_inline) {
+ if (num_vars) {
+ Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
+ -1);
+ result = JIM_ERR;
+ goto done;
+ }
+ num_vars = regex->re_nsub + 1;
+ }
+
+ pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ source_str += source_len;
+ }
+ else if (offset > 0) {
+ source_str += utf8_index(source_str, offset);
+ }
+ eflags |= REG_NOTBOL;
+ }
+
+ if (opt_inline) {
+ resultListObj = Jim_NewListObj(interp, NULL, 0);
+ }
+
+ next_match:
+ match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ jim_regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ result = JIM_ERR;
+ goto done;
+ }
+
+ if (match == REG_NOMATCH) {
+ goto done;
+ }
+
+ num_matches++;
+
+ if (opt_all && !opt_inline) {
+
+ goto try_next_match;
+ }
+
+
+ j = 0;
+ for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
+ Jim_Obj *resultObj;
+
+ if (opt_indices) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = Jim_NewStringObj(interp, "", 0);
+ }
+
+ if (pmatch[j].rm_so == -1) {
+ if (opt_indices) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ }
+ }
+ else {
+ if (opt_indices) {
+
+ int so = utf8_strlen(source_str, pmatch[j].rm_so);
+ int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
+ }
+ else {
+ Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
+ }
+ }
+
+ if (opt_inline) {
+ Jim_ListAppendElement(interp, resultListObj, resultObj);
+ }
+ else {
+
+ result = Jim_SetVariable(interp, argv[i], resultObj);
+
+ if (result != JIM_OK) {
+ Jim_FreeObj(interp, resultObj);
+ break;
+ }
+ }
+ }
+
+ try_next_match:
+ if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
+ if (pmatch[0].rm_eo) {
+ offset += utf8_strlen(source_str, pmatch[0].rm_eo);
+ source_str += pmatch[0].rm_eo;
+ }
+ else {
+ source_str++;
+ offset++;
+ }
+ if (*source_str) {
+ eflags = REG_NOTBOL;
+ goto next_match;
+ }
+ }
+
+ done:
+ if (result == JIM_OK) {
+ if (opt_inline) {
+ Jim_SetResult(interp, resultListObj);
+ }
+ else {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ }
+
+ Jim_Free(pmatch);
+ return result;
+}
+
+#define MAX_SUB_MATCHES 50
+
+int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int regcomp_flags = 0;
+ int regexec_flags = 0;
+ int opt_all = 0;
+ int opt_command = 0;
+ int offset = 0;
+ regex_t *regex;
+ const char *p;
+ int result = JIM_OK;
+ regmatch_t pmatch[MAX_SUB_MATCHES + 1];
+ int num_matches = 0;
+
+ int i, j, n;
+ Jim_Obj *varname;
+ Jim_Obj *resultObj;
+ Jim_Obj *cmd_prefix = NULL;
+ Jim_Obj *regcomp_obj = NULL;
+ const char *source_str;
+ int source_len;
+ const char *replace_str = NULL;
+ int replace_len;
+ const char *pattern;
+ int option;
+ enum {
+ OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
+ };
+ static const char * const options[] = {
+ "-nocase", "-line", "-all", "-start", "-command", "--", NULL
+ };
+
+ if (argc < 4) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-switch ...? exp string subSpec ?varName?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+
+ case OPT_COMMAND:
+ opt_command = 1;
+ break;
+ }
+ }
+ if (argc - i != 3 && argc - i != 4) {
+ goto wrongNumArgs;
+ }
+
+
+ regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
+ Jim_IncrRefCount(regcomp_obj);
+ regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
+ if (!regex) {
+ Jim_DecrRefCount(interp, regcomp_obj);
+ return JIM_ERR;
+ }
+ pattern = Jim_String(argv[i]);
+
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+ if (opt_command) {
+ cmd_prefix = argv[i + 2];
+ if (Jim_ListLength(interp, cmd_prefix) == 0) {
+ Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
+ Jim_DecrRefCount(interp, regcomp_obj);
+ return JIM_ERR;
+ }
+ Jim_IncrRefCount(cmd_prefix);
+ }
+ else {
+ replace_str = Jim_GetString(argv[i + 2], &replace_len);
+ }
+ varname = argv[i + 3];
+
+
+ resultObj = Jim_NewStringObj(interp, "", 0);
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ offset = source_len;
+ }
+ else if (offset < 0) {
+ offset = 0;
+ }
+ }
+
+ offset = utf8_index(source_str, offset);
+
+
+ Jim_AppendString(interp, resultObj, source_str, offset);
+
+
+ n = source_len - offset;
+ p = source_str + offset;
+ do {
+ int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ jim_regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ return JIM_ERR;
+ }
+ if (match == REG_NOMATCH) {
+ break;
+ }
+
+ num_matches++;
+
+ Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+
+ if (opt_command) {
+
+ Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
+ for (j = 0; j < MAX_SUB_MATCHES; j++) {
+ if (pmatch[j].rm_so == -1) {
+ break;
+ }
+ else {
+ Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
+ Jim_ListAppendElement(interp, cmdListObj, srcObj);
+ }
+ }
+ Jim_IncrRefCount(cmdListObj);
+
+ result = Jim_EvalObj(interp, cmdListObj);
+ Jim_DecrRefCount(interp, cmdListObj);
+ if (result != JIM_OK) {
+ goto cmd_error;
+ }
+ Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
+ }
+ else {
+
+ for (j = 0; j < replace_len; j++) {
+ int idx;
+ int c = replace_str[j];
+
+ if (c == '&') {
+ idx = 0;
+ }
+ else if (c == '\\' && j < replace_len) {
+ c = replace_str[++j];
+ if ((c >= '0') && (c <= '9')) {
+ idx = c - '0';
+ }
+ else if ((c == '\\') || (c == '&')) {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
+ continue;
+ }
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+ Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+ pmatch[idx].rm_eo - pmatch[idx].rm_so);
+ }
+ }
+ }
+
+ p += pmatch[0].rm_eo;
+ n -= pmatch[0].rm_eo;
+
+
+ if (!opt_all || n == 0) {
+ break;
+ }
+
+
+ if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
+ break;
+ }
+
+
+ if (pattern[0] == '\0' && n) {
+
+ Jim_AppendString(interp, resultObj, p, 1);
+ p++;
+ n--;
+ }
+
+ if (pmatch[0].rm_eo == pmatch[0].rm_so) {
+
+ regexec_flags = REG_NOTBOL;
+ }
+ else {
+ regexec_flags = 0;
+ }
+
+ } while (n);
+
+ Jim_AppendString(interp, resultObj, p, -1);
+
+cmd_error:
+ if (result == JIM_OK) {
+
+ if (argc - i == 4) {
+ result = Jim_SetVariable(interp, varname, resultObj);
+
+ if (result == JIM_OK) {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ result = JIM_OK;
+ }
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
+
+ if (opt_command) {
+ Jim_DecrRefCount(interp, cmd_prefix);
+ }
+
+ Jim_DecrRefCount(interp, regcomp_obj);
+
+ return result;
+}
+
+int Jim_regexpInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "regexp");
+ Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_UTIMES
+#include
+#endif
+#ifdef HAVE_UNISTD_H
+#include
+#elif defined(_MSC_VER)
+#include
+#define F_OK 0
+#define W_OK 2
+#define R_OK 4
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
+#define ISWINDOWS 1
+
+#undef HAVE_SYMLINK
+#else
+#define ISWINDOWS 0
+#endif
+
+
+#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
+#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
+#endif
+
+
+static void JimFixPath(char *path)
+{
+ if (ISWINDOWS) {
+
+ char *p = path;
+ while ((p = strchr(p, '\\')) != NULL) {
+ *p++ = '/';
+ }
+ }
+}
+
+
+static const char *JimGetFileType(int mode)
+{
+ if (S_ISREG(mode)) {
+ return "file";
+ }
+ else if (S_ISDIR(mode)) {
+ return "directory";
+ }
+#ifdef S_ISCHR
+ else if (S_ISCHR(mode)) {
+ return "characterSpecial";
+ }
+#endif
+#ifdef S_ISBLK
+ else if (S_ISBLK(mode)) {
+ return "blockSpecial";
+ }
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO(mode)) {
+ return "fifo";
+ }
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK(mode)) {
+ return "link";
+ }
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+#endif
+ return "unknown";
+}
+
+static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
+{
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
+}
+
+int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
+{
+
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ AppendStatElement(interp, listObj, "dev", sb->st_dev);
+ AppendStatElement(interp, listObj, "ino", sb->st_ino);
+ AppendStatElement(interp, listObj, "mode", sb->st_mode);
+ AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
+ AppendStatElement(interp, listObj, "uid", sb->st_uid);
+ AppendStatElement(interp, listObj, "gid", sb->st_gid);
+ AppendStatElement(interp, listObj, "size", sb->st_size);
+ AppendStatElement(interp, listObj, "atime", sb->st_atime);
+ AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
+ AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
+#ifdef STAT_MTIME_US
+ AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
+#endif
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
+
+
+ if (varName) {
+ Jim_Obj *objPtr;
+ objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
+
+ if (objPtr) {
+ Jim_Obj *objv[2];
+
+ objv[0] = objPtr;
+ objv[1] = listObj;
+
+ objPtr = Jim_DictMerge(interp, 2, objv);
+ if (objPtr == NULL) {
+
+ Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
+ Jim_FreeNewObj(interp, listObj);
+ return JIM_ERR;
+ }
+
+ Jim_InvalidateStringRep(objPtr);
+
+ Jim_FreeNewObj(interp, listObj);
+ listObj = objPtr;
+ }
+ Jim_SetVariable(interp, varName, listObj);
+ }
+
+
+ Jim_SetResult(interp, listObj);
+
+ return JIM_OK;
+}
+
+static int JimPathLenNoTrailingSlashes(const char *path, int len)
+{
+ int i;
+ for (i = len; i > 1 && path[i - 1] == '/'; i--) {
+
+ if (ISWINDOWS && path[i - 2] == ':') {
+
+ break;
+ }
+ }
+ return i;
+}
+
+static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int len = Jim_Length(objPtr);
+ const char *path = Jim_String(objPtr);
+ int i = JimPathLenNoTrailingSlashes(path, len);
+ if (i != len) {
+ objPtr = Jim_NewStringObj(interp, path, i);
+ }
+ Jim_IncrRefCount(objPtr);
+ return objPtr;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *p = strrchr(path, '/');
+
+ if (!p) {
+ Jim_SetResultString(interp, ".", -1);
+ }
+ else if (p[1] == 0) {
+
+ Jim_SetResult(interp, objPtr);
+ }
+ else if (p == path) {
+ Jim_SetResultString(interp, "/", -1);
+ }
+ else if (ISWINDOWS && p[-1] == ':') {
+
+ Jim_SetResultString(interp, path, p - path + 1);
+ }
+ else {
+
+ int len = JimPathLenNoTrailingSlashes(path, p - path);
+ Jim_SetResultString(interp, path, len);
+ }
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ const char *path = Jim_String(argv[0]);
+
+ if (*path == '/') {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
+ }
+
+ while (1) {
+
+ while (*path == '/') {
+ path++;
+ }
+ if (*path) {
+ const char *pt = strchr(path, '/');
+ if (pt) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
+ path = pt;
+ continue;
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
+ }
+ break;
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+ Jim_SetResult(interp, argv[0]);
+ }
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+ p = "";
+ }
+ Jim_SetResultString(interp, p, -1);
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+ const char *path = Jim_String(objPtr);
+ const char *lastSlash = strrchr(path, '/');
+
+ if (lastSlash) {
+ Jim_SetResultString(interp, lastSlash + 1, -1);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+#ifndef HAVE_RESTRICT
+#define restrict
+#endif
+
+static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
+{
+#if defined(HAVE__FULLPATH)
+ return _fullpath(resolved_path, path, len);
+#elif defined(HAVE_REALPATH)
+ return realpath(path, resolved_path);
+#else
+ return NULL;
+#endif
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ char *newname = Jim_Alloc(MAXPATHLEN);
+
+ if (JimRealPath(path, newname, MAXPATHLEN)) {
+ JimFixPath(newname);
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+ return JIM_OK;
+ }
+ Jim_Free(newname);
+ Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+}
+
+static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ char *newname = Jim_Alloc(MAXPATHLEN + 1);
+ char *last = newname;
+
+ *newname = 0;
+
+
+ for (i = 0; i < argc; i++) {
+ int len;
+ const char *part = Jim_GetString(argv[i], &len);
+
+ if (*part == '/') {
+
+ last = newname;
+ }
+ else if (ISWINDOWS && strchr(part, ':')) {
+
+ last = newname;
+ }
+ else if (part[0] == '.') {
+ if (part[1] == '/') {
+ part += 2;
+ len -= 2;
+ }
+ else if (part[1] == 0 && last != newname) {
+
+ continue;
+ }
+ }
+
+
+ if (last != newname && last[-1] != '/') {
+ *last++ = '/';
+ }
+
+ if (len) {
+ if (last + len - newname >= MAXPATHLEN) {
+ Jim_Free(newname);
+ Jim_SetResultString(interp, "Path too long", -1);
+ return JIM_ERR;
+ }
+ memcpy(last, part, len);
+ last += len;
+ }
+
+
+ if (last > newname + 1 && last[-1] == '/') {
+
+ if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
+ *--last = 0;
+ }
+ }
+ }
+
+ *last = 0;
+
+
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
+
+ return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+ Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
+
+ return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef X_OK
+ return file_access(interp, argv[0], X_OK);
+#else
+
+ Jim_SetResultBool(interp, 1);
+ return JIM_OK;
+#endif
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
+
+ if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
+ argc--;
+ argv++;
+ }
+
+ while (argc--) {
+ const char *path = Jim_String(argv[0]);
+
+ if (unlink(path) == -1 && errno != ENOENT) {
+ if (rmdir(path) == -1) {
+
+ if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ }
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+#ifdef HAVE_MKDIR_ONE_ARG
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
+#else
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
+#endif
+
+static int mkdir_all(char *path)
+{
+ int ok = 1;
+
+
+ goto first;
+
+ while (ok--) {
+
+ {
+ char *slash = strrchr(path, '/');
+
+ if (slash && slash != path) {
+ *slash = 0;
+ if (mkdir_all(path) != 0) {
+ return -1;
+ }
+ *slash = '/';
+ }
+ }
+ first:
+ if (MKDIR_DEFAULT(path) == 0) {
+ return 0;
+ }
+ if (errno == ENOENT) {
+
+ continue;
+ }
+
+ if (errno == EEXIST) {
+ jim_stat_t sb;
+
+ if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ return 0;
+ }
+
+ errno = EEXIST;
+ }
+
+ break;
+ }
+ return -1;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ while (argc--) {
+ char *path = Jim_StrDup(Jim_String(argv[0]));
+ int rc = mkdir_all(path);
+
+ Jim_Free(path);
+ if (rc != 0) {
+ Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
+ strerror(errno));
+ return JIM_ERR;
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
+
+ if (fd < 0) {
+ return JIM_ERR;
+ }
+ close(fd);
+
+ return JIM_OK;
+}
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *source;
+ const char *dest;
+ int force = 0;
+
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
+ return -1;
+ }
+ force++;
+ argv++;
+ argc--;
+ }
+
+ source = Jim_String(argv[0]);
+ dest = Jim_String(argv[1]);
+
+ if (!force && access(dest, F_OK) == 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
+ argv[1]);
+ return JIM_ERR;
+ }
+#if ISWINDOWS
+ if (access(dest, F_OK) == 0) {
+
+ remove(dest);
+ }
+#endif
+ if (rename(source, dest) != 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+ strerror(errno));
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
+static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int ret;
+ const char *source;
+ const char *dest;
+ static const char * const options[] = { "-hard", "-symbolic", NULL };
+ enum { OPT_HARD, OPT_SYMBOLIC, };
+ int option = OPT_HARD;
+
+ if (argc == 3) {
+ if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ argv++;
+ argc--;
+ }
+
+ dest = Jim_String(argv[0]);
+ source = Jim_String(argv[1]);
+
+ if (option == OPT_HARD) {
+ ret = link(source, dest);
+ }
+ else {
+ ret = symlink(source, dest);
+ }
+
+ if (ret != 0) {
+ Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+ strerror(errno));
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+#endif
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (Jim_Stat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+#ifdef Jim_LinkStat
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (Jim_LinkStat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+#else
+#define file_lstat file_stat
+#endif
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_atime);
+ return JIM_OK;
+}
+
+static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
+{
+#ifdef HAVE_UTIMES
+ struct timeval times[2];
+
+ times[1].tv_sec = times[0].tv_sec = us / 1000000;
+ times[1].tv_usec = times[0].tv_usec = us % 1000000;
+
+ if (utimes(filename, times) != 0) {
+ Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+#else
+ Jim_SetResultString(interp, "Not implemented", -1);
+ return JIM_ERR;
+#endif
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (argc == 2) {
+ jim_wide secs;
+ if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
+ }
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_mtime);
+ return JIM_OK;
+}
+
+#ifdef STAT_MTIME_US
+static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (argc == 2) {
+ jim_wide us;
+ if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JimSetFileTimes(interp, Jim_String(argv[0]), us);
+ }
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, STAT_MTIME_US(sb));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_EvalPrefix(interp, "file copy", argc, argv);
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_size);
+ return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISDIR(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISREG(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+#ifdef HAVE_GETEUID
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = (geteuid() == sb.st_uid);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+#endif
+
+#if defined(HAVE_READLINK)
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+ int linkLength = readlink(path, linkValue, MAXPATHLEN);
+
+ if (linkLength == -1) {
+ Jim_Free(linkValue);
+ Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+ }
+ linkValue[linkLength] = 0;
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
+ return JIM_OK;
+}
+
+#ifdef Jim_LinkStat
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+}
+#else
+#define file_cmd_lstat file_cmd_stat
+#endif
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_stat_t sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+}
+
+static const jim_subcmd_type file_command_table[] = {
+ { "atime",
+ "name",
+ file_cmd_atime,
+ 1,
+ 1,
+
+ },
+ { "mtime",
+ "name ?time?",
+ file_cmd_mtime,
+ 1,
+ 2,
+
+ },
+#ifdef STAT_MTIME_US
+ { "mtimeus",
+ "name ?time?",
+ file_cmd_mtimeus,
+ 1,
+ 2,
+
+ },
+#endif
+ { "copy",
+ "?-force? source dest",
+ file_cmd_copy,
+ 2,
+ 3,
+
+ },
+ { "dirname",
+ "name",
+ file_cmd_dirname,
+ 1,
+ 1,
+
+ },
+ { "rootname",
+ "name",
+ file_cmd_rootname,
+ 1,
+ 1,
+
+ },
+ { "extension",
+ "name",
+ file_cmd_extension,
+ 1,
+ 1,
+
+ },
+ { "tail",
+ "name",
+ file_cmd_tail,
+ 1,
+ 1,
+
+ },
+ { "split",
+ "name",
+ file_cmd_split,
+ 1,
+ 1,
+
+ },
+ { "normalize",
+ "name",
+ file_cmd_normalize,
+ 1,
+ 1,
+
+ },
+ { "join",
+ "name ?name ...?",
+ file_cmd_join,
+ 1,
+ -1,
+
+ },
+ { "readable",
+ "name",
+ file_cmd_readable,
+ 1,
+ 1,
+
+ },
+ { "writable",
+ "name",
+ file_cmd_writable,
+ 1,
+ 1,
+
+ },
+ { "executable",
+ "name",
+ file_cmd_executable,
+ 1,
+ 1,
+
+ },
+ { "exists",
+ "name",
+ file_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "delete",
+ "?-force|--? name ...",
+ file_cmd_delete,
+ 1,
+ -1,
+
+ },
+ { "mkdir",
+ "dir ...",
+ file_cmd_mkdir,
+ 1,
+ -1,
+
+ },
+ { "tempfile",
+ "?template?",
+ file_cmd_tempfile,
+ 0,
+ 1,
+
+ },
+ { "rename",
+ "?-force? source dest",
+ file_cmd_rename,
+ 2,
+ 3,
+
+ },
+#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
+ { "link",
+ "?-symbolic|-hard? newname target",
+ file_cmd_link,
+ 2,
+ 3,
+
+ },
+#endif
+#if defined(HAVE_READLINK)
+ { "readlink",
+ "name",
+ file_cmd_readlink,
+ 1,
+ 1,
+
+ },
+#endif
+ { "size",
+ "name",
+ file_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "stat",
+ "name ?var?",
+ file_cmd_stat,
+ 1,
+ 2,
+
+ },
+ { "lstat",
+ "name ?var?",
+ file_cmd_lstat,
+ 1,
+ 2,
+
+ },
+ { "type",
+ "name",
+ file_cmd_type,
+ 1,
+ 1,
+
+ },
+#ifdef HAVE_GETEUID
+ { "owned",
+ "name",
+ file_cmd_owned,
+ 1,
+ 1,
+
+ },
+#endif
+ { "isdirectory",
+ "name",
+ file_cmd_isdirectory,
+ 1,
+ 1,
+
+ },
+ { "isfile",
+ "name",
+ file_cmd_isfile,
+ 1,
+ 1,
+
+ },
+ {
+ NULL
+ }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "dirname");
+ return JIM_ERR;
+ }
+
+ path = Jim_String(argv[1]);
+
+ if (chdir(path) != 0) {
+ Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ char *cwd = Jim_Alloc(MAXPATHLEN);
+
+ if (getcwd(cwd, MAXPATHLEN) == NULL) {
+ Jim_SetResultString(interp, "Failed to get pwd", -1);
+ Jim_Free(cwd);
+ return JIM_ERR;
+ }
+ JimFixPath(cwd);
+ Jim_SetResultString(interp, cwd, -1);
+
+ Jim_Free(cwd);
+ return JIM_OK;
+}
+
+int Jim_fileInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "file");
+ Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
+ Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+
+
+#if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+ int i, j;
+ int rc;
+
+
+ for (i = 1; i < argc; i++) {
+ int len;
+ const char *arg = Jim_GetString(argv[i], &len);
+
+ if (i > 1) {
+ Jim_AppendString(interp, cmdlineObj, " ", 1);
+ }
+ if (strpbrk(arg, "\\\" ") == NULL) {
+
+ Jim_AppendString(interp, cmdlineObj, arg, len);
+ continue;
+ }
+
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ for (j = 0; j < len; j++) {
+ if (arg[j] == '\\' || arg[j] == '"') {
+ Jim_AppendString(interp, cmdlineObj, "\\", 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ }
+ rc = system(Jim_String(cmdlineObj));
+
+ Jim_FreeNewObj(interp, cmdlineObj);
+
+ if (rc) {
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "exec");
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+ return JIM_OK;
+}
+#else
+
+
+#include
+#include
+#include
+
+struct WaitInfoTable;
+
+static char **JimOriginalEnviron(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+ phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj);
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+#if defined(__MINGW32__)
+static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
+#endif
+
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+}
+
+static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
+{
+ char buf[256];
+ int ret = 0;
+
+ while (1) {
+ int retval = read(fd, buf, sizeof(buf));
+ if (retval > 0) {
+ ret = 1;
+ Jim_AppendString(interp, strObj, buf, retval);
+ }
+ if (retval <= 0) {
+ break;
+ }
+ }
+ close(fd);
+ return ret;
+}
+
+static char **JimBuildEnv(Jim_Interp *interp)
+{
+ int i;
+ int size;
+ int num;
+ int n;
+ char **envptr;
+ char *envdata;
+
+ Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
+
+ if (!objPtr) {
+ return JimOriginalEnviron();
+ }
+
+
+
+ num = Jim_ListLength(interp, objPtr);
+ if (num % 2) {
+
+ num--;
+ }
+ size = Jim_Length(objPtr) + 2;
+
+ envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+ envdata = (char *)&envptr[num / 2 + 1];
+
+ n = 0;
+ for (i = 0; i < num; i += 2) {
+ const char *s1, *s2;
+ Jim_Obj *elemObj;
+
+ Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
+ s1 = Jim_String(elemObj);
+ Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
+ s2 = Jim_String(elemObj);
+
+ envptr[n] = envdata;
+ envdata += sprintf(envdata, "%s=%s", s1, s2);
+ envdata++;
+ n++;
+ }
+ envptr[n] = NULL;
+ *envdata = 0;
+
+ return envptr;
+}
+
+static void JimFreeEnv(char **env, char **original_environ)
+{
+ if (env != original_environ) {
+ Jim_Free(env);
+ }
+}
+
+static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
+{
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+
+ if (pid <= 0) {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
+ }
+ else if (WIFEXITED(waitStatus)) {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
+ }
+ else {
+ const char *type;
+ const char *action;
+ const char *signame;
+
+ if (WIFSIGNALED(waitStatus)) {
+ type = "CHILDKILLED";
+ action = "killed";
+ signame = Jim_SignalId(WTERMSIG(waitStatus));
+ }
+ else {
+ type = "CHILDSUSP";
+ action = "suspended";
+ signame = "none";
+ }
+
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
+
+ if (errStrObj) {
+ Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
+ }
+
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
+ }
+ return errorCode;
+}
+
+static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
+{
+ if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
+ return JIM_OK;
+ }
+ Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
+
+ return JIM_ERR;
+}
+
+
+struct WaitInfo
+{
+ phandle_t phandle;
+ int status;
+ int flags;
+};
+
+
+struct WaitInfoTable {
+ struct WaitInfo *info;
+ int size;
+ int used;
+ int refcount;
+};
+
+
+#define WI_DETACHED 2
+
+#define WAIT_TABLE_GROW_BY 4
+
+static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
+{
+ struct WaitInfoTable *table = privData;
+
+ if (--table->refcount == 0) {
+ Jim_Free(table->info);
+ Jim_Free(table);
+ }
+}
+
+static struct WaitInfoTable *JimAllocWaitInfoTable(void)
+{
+ struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
+ table->info = NULL;
+ table->size = table->used = 0;
+ table->refcount = 1;
+
+ return table;
+}
+
+static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle)
+{
+ int i;
+
+
+ for (i = 0; i < table->used; i++) {
+ if (phandle == table->info[i].phandle) {
+ if (i != table->used - 1) {
+ table->info[i] = table->info[table->used - 1];
+ }
+ table->used--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int outputId;
+ int errorId;
+ phandle_t *pidPtr;
+ int numPids, result;
+ int child_siginfo = 1;
+ Jim_Obj *childErrObj;
+ Jim_Obj *errStrObj;
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+ Jim_Obj *listObj;
+ int i;
+
+ argc--;
+ numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = 0; i < numPids; i++) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i])));
+ }
+ Jim_SetResult(interp, listObj);
+ JimDetachPids(table, numPids, pidPtr);
+ Jim_Free(pidPtr);
+ return JIM_OK;
+ }
+
+ numPids =
+ JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ result = JIM_OK;
+
+ errStrObj = Jim_NewStringObj(interp, "", 0);
+
+
+ if (outputId != -1) {
+ if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
+ result = JIM_ERR;
+ Jim_SetResultErrno(interp, "error reading from output pipe");
+ }
+ }
+
+
+ childErrObj = Jim_NewStringObj(interp, "", 0);
+ Jim_IncrRefCount(childErrObj);
+
+ if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
+ result = JIM_ERR;
+ }
+
+ if (errorId != -1) {
+ int ret;
+ Jim_Lseek(errorId, 0, SEEK_SET);
+ ret = JimAppendStreamToString(interp, errorId, errStrObj);
+ if (ret < 0) {
+ Jim_SetResultErrno(interp, "error reading from error pipe");
+ result = JIM_ERR;
+ }
+ else if (ret > 0) {
+
+ child_siginfo = 0;
+ }
+ }
+
+ if (child_siginfo) {
+
+ Jim_AppendObj(interp, errStrObj, childErrObj);
+ }
+ Jim_DecrRefCount(interp, childErrObj);
+
+
+ Jim_RemoveTrailingNewline(errStrObj);
+
+
+ Jim_SetResult(interp, errStrObj);
+
+ return result;
+}
+
+static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr)
+{
+ if (JimWaitRemove(table, phandle) == 0) {
+
+ return waitpid(phandle, statusPtr, 0);
+ }
+
+
+ return -1;
+}
+
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr)
+{
+ int j;
+
+ for (j = 0; j < numPids; j++) {
+
+ int i;
+ for (i = 0; i < table->used; i++) {
+ if (pidPtr[j] == table->info[i].phandle) {
+ table->info[i].flags |= WI_DETACHED;
+ break;
+ }
+ }
+ }
+}
+
+static int JimGetChannelFd(Jim_Interp *interp, const char *name)
+{
+ Jim_Obj *objv[2];
+
+ objv[0] = Jim_NewStringObj(interp, name, -1);
+ objv[1] = Jim_NewStringObj(interp, "getfd", -1);
+
+ if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
+ jim_wide fd;
+ if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
+ return fd;
+ }
+ }
+ return -1;
+}
+
+static void JimReapDetachedPids(struct WaitInfoTable *table)
+{
+ struct WaitInfo *waitPtr;
+ int count;
+ int dest;
+
+ if (!table) {
+ return;
+ }
+
+ waitPtr = table->info;
+ dest = 0;
+ for (count = table->used; count > 0; waitPtr++, count--) {
+ if (waitPtr->flags & WI_DETACHED) {
+ int status;
+ long pid = waitpid(waitPtr->phandle, &status, WNOHANG);
+ if (pid > 0) {
+
+ table->used--;
+ continue;
+ }
+ }
+ if (waitPtr != &table->info[dest]) {
+ table->info[dest] = *waitPtr;
+ }
+ dest++;
+ }
+}
+
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+ int nohang = 0;
+ long pid;
+ phandle_t phandle;
+ int status;
+ Jim_Obj *errCodeObj;
+
+
+ if (argc == 1) {
+ JimReapDetachedPids(table);
+ return JIM_OK;
+ }
+
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
+ nohang = 1;
+ }
+ if (argc != nohang + 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
+ return JIM_ERR;
+ }
+ if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+
+ phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0);
+ if (phandle == JIM_BAD_PHANDLE) {
+ pid = -1;
+ }
+#ifndef __MINGW32__
+ else if (pid < 0) {
+ pid = phandle;
+ }
+#endif
+
+ errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
+
+ if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) {
+
+ JimWaitRemove(table, phandle);
+ }
+ Jim_SetResult(interp, errCodeObj);
+ return JIM_OK;
+}
+
+static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+
+ Jim_SetResultInt(interp, (jim_wide)getpid());
+ return JIM_OK;
+}
+
+static int
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr,
+ int *inPipePtr, int *outPipePtr, int *errFilePtr)
+{
+ phandle_t *pidPtr = NULL; /* Points to alloc-ed array holding all
+ * the pids of child processes. */
+ int numPids = 0; /* Actual number of processes that exist
+ * at *pidPtr right now. */
+ int cmdCount; /* Count of number of distinct commands
+ * found in argc/argv. */
+ const char *input = NULL; /* Describes input for pipeline, depending
+ * on "inputFile". NULL means take input
+ * from stdin/pipe. */
+ int input_len = 0;
+
+#define FILE_NAME 0
+#define FILE_APPEND 1
+#define FILE_HANDLE 2
+#define FILE_TEXT 3
+
+ int inputFile = FILE_NAME; /* 1 means input is name of input file.
+ * 2 means input is filehandle name.
+ * 0 means input holds actual
+ * text to be input to command. */
+
+ int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+ * 1 means output is the name of output file, and append.
+ * 2 means output is filehandle name.
+ * All this is ignored if output is NULL
+ */
+ int errorFile = FILE_NAME; /* 0 means error is the name of error file.
+ * 1 means error is the name of error file, and append.
+ * 2 means error is filehandle name.
+ * All this is ignored if error is NULL
+ */
+ const char *output = NULL; /* Holds name of output file to pipe to,
+ * or NULL if output goes to stdout/pipe. */
+ const char *error = NULL; /* Holds name of stderr file to pipe to,
+ * or NULL if stderr goes to stderr/pipe. */
+ int inputId = -1;
+ int outputId = -1;
+ int errorId = -1;
+ int lastOutputId = -1;
+ int pipeIds[2];
+ int firstArg, lastArg; /* Indexes of first and last arguments in
+ * current command. */
+ int lastBar;
+ int i;
+ phandle_t phandle;
+ char **save_environ;
+#if defined(HAVE_EXECVPE) && !defined(__MINGW32__)
+ char **child_environ;
+#endif
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+
+ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+ int arg_count = 0;
+
+ if (inPipePtr != NULL) {
+ *inPipePtr = -1;
+ }
+ if (outPipePtr != NULL) {
+ *outPipePtr = -1;
+ }
+ if (errFilePtr != NULL) {
+ *errFilePtr = -1;
+ }
+ pipeIds[0] = pipeIds[1] = -1;
+
+ cmdCount = 1;
+ lastBar = -1;
+ for (i = 0; i < argc; i++) {
+ const char *arg = Jim_String(argv[i]);
+
+ if (arg[0] == '<') {
+ inputFile = FILE_NAME;
+ input = arg + 1;
+ if (*input == '<') {
+ inputFile = FILE_TEXT;
+ input_len = Jim_Length(argv[i]) - 2;
+ input++;
+ }
+ else if (*input == '@') {
+ inputFile = FILE_HANDLE;
+ input++;
+ }
+
+ if (!*input && ++i < argc) {
+ input = Jim_GetString(argv[i], &input_len);
+ }
+ }
+ else if (arg[0] == '>') {
+ int dup_error = 0;
+
+ outputFile = FILE_NAME;
+
+ output = arg + 1;
+ if (*output == '>') {
+ outputFile = FILE_APPEND;
+ output++;
+ }
+ if (*output == '&') {
+
+ output++;
+ dup_error = 1;
+ }
+ if (*output == '@') {
+ outputFile = FILE_HANDLE;
+ output++;
+ }
+ if (!*output && ++i < argc) {
+ output = Jim_String(argv[i]);
+ }
+ if (dup_error) {
+ errorFile = outputFile;
+ error = output;
+ }
+ }
+ else if (arg[0] == '2' && arg[1] == '>') {
+ error = arg + 2;
+ errorFile = FILE_NAME;
+
+ if (*error == '@') {
+ errorFile = FILE_HANDLE;
+ error++;
+ }
+ else if (*error == '>') {
+ errorFile = FILE_APPEND;
+ error++;
+ }
+ if (!*error && ++i < argc) {
+ error = Jim_String(argv[i]);
+ }
+ }
+ else {
+ if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
+ if (i == lastBar + 1 || i == argc - 1) {
+ Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
+ goto badargs;
+ }
+ lastBar = i;
+ cmdCount++;
+ }
+
+ arg_array[arg_count++] = (char *)arg;
+ continue;
+ }
+
+ if (i >= argc) {
+ Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
+ goto badargs;
+ }
+ }
+
+ if (arg_count == 0) {
+ Jim_SetResultString(interp, "didn't specify command to execute", -1);
+badargs:
+ Jim_Free(arg_array);
+ return -1;
+ }
+
+
+ save_environ = JimSaveEnv(JimBuildEnv(interp));
+
+ if (input != NULL) {
+ if (inputFile == FILE_TEXT) {
+ inputId = Jim_MakeTempFile(interp, NULL, 1);
+ if (inputId == -1) {
+ goto error;
+ }
+ if (write(inputId, input, input_len) != input_len) {
+ Jim_SetResultErrno(interp, "couldn't write temp file");
+ close(inputId);
+ goto error;
+ }
+ Jim_Lseek(inputId, 0L, SEEK_SET);
+ }
+ else if (inputFile == FILE_HANDLE) {
+ int fd = JimGetChannelFd(interp, input);
+
+ if (fd < 0) {
+ goto error;
+ }
+ inputId = dup(fd);
+ }
+ else {
+ inputId = Jim_OpenForRead(input);
+ if (inputId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (inPipePtr != NULL) {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+ goto error;
+ }
+ inputId = pipeIds[0];
+ *inPipePtr = pipeIds[1];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ if (output != NULL) {
+ if (outputFile == FILE_HANDLE) {
+ int fd = JimGetChannelFd(interp, output);
+ if (fd < 0) {
+ goto error;
+ }
+ lastOutputId = dup(fd);
+ }
+ else {
+ lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
+ if (lastOutputId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (outPipePtr != NULL) {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create output pipe");
+ goto error;
+ }
+ lastOutputId = pipeIds[1];
+ *outPipePtr = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ if (error != NULL) {
+ if (errorFile == FILE_HANDLE) {
+ if (strcmp(error, "1") == 0) {
+
+ if (lastOutputId != -1) {
+ errorId = dup(lastOutputId);
+ }
+ else {
+
+ error = "stdout";
+ }
+ }
+ if (errorId == -1) {
+ int fd = JimGetChannelFd(interp, error);
+ if (fd < 0) {
+ goto error;
+ }
+ errorId = dup(fd);
+ }
+ }
+ else {
+ errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
+ if (errorId == -1) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
+ goto error;
+ }
+ }
+ }
+ else if (errFilePtr != NULL) {
+ errorId = Jim_MakeTempFile(interp, NULL, 1);
+ if (errorId == -1) {
+ goto error;
+ }
+ *errFilePtr = dup(errorId);
+ }
+
+
+ pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
+ for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
+ int pipe_dup_err = 0;
+ int origErrorId = errorId;
+
+ for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+ if (strcmp(arg_array[lastArg], "|") == 0) {
+ break;
+ }
+ if (strcmp(arg_array[lastArg], "|&") == 0) {
+ pipe_dup_err = 1;
+ break;
+ }
+ }
+
+ if (lastArg == firstArg) {
+ Jim_SetResultString(interp, "missing command to exec", -1);
+ goto error;
+ }
+
+
+ arg_array[lastArg] = NULL;
+ if (lastArg == arg_count) {
+ outputId = lastOutputId;
+ lastOutputId = -1;
+ }
+ else {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create pipe");
+ goto error;
+ }
+ outputId = pipeIds[1];
+ }
+
+
+ if (pipe_dup_err) {
+ errorId = outputId;
+ }
+
+
+
+#ifdef __MINGW32__
+ phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
+ if (phandle == JIM_BAD_PHANDLE) {
+ Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+ goto error;
+ }
+#else
+ i = strlen(arg_array[firstArg]);
+
+#ifdef HAVE_EXECVPE
+ child_environ = Jim_GetEnviron();
+#endif
+#ifdef HAVE_VFORK
+ phandle = vfork();
+#else
+ phandle = fork();
+#endif
+ if (phandle < 0) {
+ Jim_SetResultErrno(interp, "couldn't fork child process");
+ goto error;
+ }
+ if (phandle == 0) {
+
+
+ if (inputId != -1 && inputId != fileno(stdin)) {
+ dup2(inputId, fileno(stdin));
+ close(inputId);
+ }
+ if (outputId != -1 && outputId != fileno(stdout)) {
+ dup2(outputId, fileno(stdout));
+ if (outputId != errorId) {
+ close(outputId);
+ }
+ }
+ if (errorId != -1 && errorId != fileno(stderr)) {
+ dup2(errorId, fileno(stderr));
+ close(errorId);
+ }
+
+ if (outPipePtr && *outPipePtr != -1) {
+ close(*outPipePtr);
+ }
+ if (errFilePtr && *errFilePtr != -1) {
+ close(*errFilePtr);
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (lastOutputId != -1) {
+ close(lastOutputId);
+ }
+
+ execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
+
+ if (write(fileno(stderr), "couldn't exec \"", 15) &&
+ write(fileno(stderr), arg_array[firstArg], i) &&
+ write(fileno(stderr), "\"\n", 2)) {
+
+ }
+#ifdef JIM_MAINTAINER
+ {
+
+ static char *const false_argv[2] = {"false", NULL};
+ execvp(false_argv[0],false_argv);
+ }
+#endif
+ _exit(127);
+ }
+#endif
+
+
+
+ if (table->used == table->size) {
+ table->size += WAIT_TABLE_GROW_BY;
+ table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
+ }
+
+ table->info[table->used].phandle = phandle;
+ table->info[table->used].flags = 0;
+ table->used++;
+
+ pidPtr[numPids] = phandle;
+
+
+ errorId = origErrorId;
+
+
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (outputId != -1) {
+ close(outputId);
+ }
+ inputId = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+ *pidArrayPtr = pidPtr;
+
+
+ cleanup:
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (lastOutputId != -1) {
+ close(lastOutputId);
+ }
+ if (errorId != -1) {
+ close(errorId);
+ }
+ Jim_Free(arg_array);
+
+ JimRestoreEnv(save_environ);
+
+ return numPids;
+
+
+ error:
+ if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
+ close(*inPipePtr);
+ *inPipePtr = -1;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
+ close(*outPipePtr);
+ *outPipePtr = -1;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
+ close(*errFilePtr);
+ *errFilePtr = -1;
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (pipeIds[1] != -1) {
+ close(pipeIds[1]);
+ }
+ if (pidPtr != NULL) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != JIM_BAD_PHANDLE) {
+ JimDetachPids(table, 1, &pidPtr[i]);
+ }
+ }
+ Jim_Free(pidPtr);
+ }
+ numPids = -1;
+ goto cleanup;
+}
+
+
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj)
+{
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+ int result = JIM_OK;
+ int i;
+
+
+ for (i = 0; i < numPids; i++) {
+ int waitStatus = 0;
+ long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus);
+ if (pid > 0) {
+ if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ }
+ }
+ Jim_Free(pidPtr);
+
+ return result;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ struct WaitInfoTable *waitinfo;
+
+ Jim_PackageProvideCheck(interp, "exec");
+
+ waitinfo = JimAllocWaitInfoTable();
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
+ waitinfo->refcount++;
+ Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
+ Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
+
+ return JIM_OK;
+}
+
+#if defined(__MINGW32__)
+
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+ int i;
+ static char extensions[][5] = {".exe", "", ".bat"};
+
+ for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+ snprintf(fullPath, MAX_PATH, "%s%s", originalName, extensions[i]);
+
+ if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+ continue;
+ }
+ if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+ continue;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+ return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(env, Jim_GetEnviron());
+}
+
+static char **JimOriginalEnviron(void)
+{
+ return NULL;
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+ char *start, *special;
+ int quote, i;
+
+ Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+ for (i = 0; argv[i]; i++) {
+ if (i > 0) {
+ Jim_AppendString(interp, strObj, " ", 1);
+ }
+
+ if (argv[i][0] == '\0') {
+ quote = 1;
+ }
+ else {
+ quote = 0;
+ for (start = argv[i]; *start != '\0'; start++) {
+ if (isspace(UCHAR(*start))) {
+ quote = 1;
+ break;
+ }
+ }
+ }
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"" , 1);
+ }
+
+ start = argv[i];
+ for (special = argv[i]; ; ) {
+ if ((*special == '\\') && (special[1] == '\\' ||
+ special[1] == '"' || (quote && special[1] == '\0'))) {
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ while (1) {
+ special++;
+ if (*special == '"' || (quote && *special == '\0')) {
+
+ Jim_AppendString(interp, strObj, start, special - start);
+ break;
+ }
+ if (*special != '\\') {
+ break;
+ }
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ }
+ if (*special == '"') {
+ if (special == start) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ else {
+ Jim_AppendString(interp, strObj, start, special - start);
+ }
+ Jim_AppendString(interp, strObj, "\\\"", 2);
+ start = special + 1;
+ }
+ if (*special == '\0') {
+ break;
+ }
+ special++;
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ }
+ return strObj;
+}
+
+static phandle_t
+JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
+{
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ HANDLE hProcess;
+ char execPath[MAX_PATH];
+ phandle_t phandle = INVALID_HANDLE_VALUE;
+ Jim_Obj *cmdLineObj;
+ char *winenv;
+
+ if (JimWinFindExecutable(argv[0], execPath) < 0) {
+ return phandle;
+ }
+ argv[0] = execPath;
+
+ hProcess = GetCurrentProcess();
+ cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+
+ ZeroMemory(&startInfo, sizeof(startInfo));
+ startInfo.cb = sizeof(startInfo);
+ startInfo.dwFlags = STARTF_USESTDHANDLES;
+ startInfo.hStdInput = INVALID_HANDLE_VALUE;
+ startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+ startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+ if (inputId == -1) {
+ inputId = _fileno(stdin);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+ if (outputId == -1) {
+ outputId = _fileno(stdout);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+
+ if (errorId == -1) {
+ errorId = _fileno(stderr);
+ }
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
+ goto end;
+ }
+
+ if (env == NULL) {
+
+ winenv = NULL;
+ }
+ else if (env[0] == NULL) {
+ winenv = (char *)"\0";
+ }
+ else {
+ winenv = env[0];
+ }
+
+ if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+ 0, winenv, NULL, &startInfo, &procInfo)) {
+ goto end;
+ }
+
+
+ WaitForInputIdle(procInfo.hProcess, 5000);
+ CloseHandle(procInfo.hThread);
+
+ phandle = procInfo.hProcess;
+
+ end:
+ Jim_FreeNewObj(interp, cmdLineObj);
+ if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdInput);
+ }
+ if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdOutput);
+ }
+ if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
+ CloseHandle(startInfo.hStdError);
+ }
+ return phandle;
+}
+
+#else
+
+static char **JimOriginalEnviron(void)
+{
+ return Jim_GetEnviron();
+}
+
+static char **JimSaveEnv(char **env)
+{
+ char **saveenv = Jim_GetEnviron();
+ Jim_SetEnviron(env);
+ return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(Jim_GetEnviron(), env);
+ Jim_SetEnviron(env);
+}
+#endif
+#endif
+
+
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+
+struct clock_options {
+ int gmt;
+ const char *format;
+};
+
+static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
+{
+ static const char * const options[] = { "-gmt", "-format", NULL };
+ enum { OPT_GMT, OPT_FORMAT, };
+ int i;
+
+ for (i = 0; i < argc; i += 2) {
+ int option;
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_GMT:
+ if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ case OPT_FORMAT:
+ opts->format = Jim_String(argv[i + 1]);
+ break;
+ }
+ }
+ return JIM_OK;
+}
+
+static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ char buf[100];
+ time_t t;
+ jim_wide seconds;
+ struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
+ struct tm *tm;
+
+ if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (argc % 2 == 0) {
+ return -1;
+ }
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
+ return JIM_ERR;
+ }
+
+ t = seconds;
+ tm = options.gmt ? gmtime(&t) : localtime(&t);
+
+ if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
+ Jim_SetResultString(interp, "format string too long or invalid time", -1);
+ return JIM_ERR;
+ }
+
+ Jim_SetResultString(interp, buf, -1);
+
+ return JIM_OK;
+}
+
+#ifdef HAVE_STRPTIME
+static time_t jim_timegm(const struct tm *tm)
+{
+ int m = tm->tm_mon + 1;
+ int y = 1900 + tm->tm_year - (m <= 2);
+ int era = (y >= 0 ? y : y - 399) / 400;
+ unsigned yoe = (unsigned)(y - era * 400);
+ unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
+ unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
+ long days = (era * 146097 + (int)doe - 719468);
+ int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+
+ return days * 24 * 60 * 60 + secs;
+}
+
+static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ char *pt;
+ struct tm tm;
+ time_t now = time(NULL);
+
+ struct clock_options options = { 0, NULL };
+
+ if (argc % 2 == 0) {
+ return -1;
+ }
+
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ if (options.format == NULL) {
+ return -1;
+ }
+
+ localtime_r(&now, &tm);
+
+ pt = strptime(Jim_String(argv[0]), options.format, &tm);
+ if (pt == 0 || *pt != 0) {
+ Jim_SetResultString(interp, "Failed to parse time according to format", -1);
+ return JIM_ERR;
+ }
+
+
+ tm.tm_isdst = options.gmt ? 0 : -1;
+ Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
+
+ return JIM_OK;
+}
+#endif
+
+static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
+ return JIM_OK;
+}
+
+static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
+ return JIM_OK;
+}
+
+static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
+ return JIM_OK;
+}
+
+static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
+ return JIM_OK;
+}
+
+static const jim_subcmd_type clock_command_table[] = {
+ { "clicks",
+ NULL,
+ clock_cmd_clicks,
+ 0,
+ 0,
+
+ },
+ { "format",
+ "seconds ?-format string? ?-gmt boolean?",
+ clock_cmd_format,
+ 1,
+ 5,
+
+ },
+ { "microseconds",
+ NULL,
+ clock_cmd_micros,
+ 0,
+ 0,
+
+ },
+ { "milliseconds",
+ NULL,
+ clock_cmd_millis,
+ 0,
+ 0,
+
+ },
+#ifdef HAVE_STRPTIME
+ { "scan",
+ "str -format format ?-gmt boolean?",
+ clock_cmd_scan,
+ 3,
+ 5,
+
+ },
+#endif
+ { "seconds",
+ NULL,
+ clock_cmd_seconds,
+ 0,
+ 0,
+
+ },
+ { NULL }
+};
+
+int Jim_clockInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "clock");
+ Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+#include
+#include
+#include
+
+
+static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
+ Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
+ return JIM_OK;
+}
+
+static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ Jim_Obj *patternObj;
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ patternObj = (argc == 1) ? NULL : argv[1];
+
+
+ if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
+ if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
+
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+
+ return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
+}
+
+static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
+}
+
+static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *resultObj;
+ Jim_Obj *objPtr;
+ Jim_Obj **dictValuesObj;
+
+ if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+
+ Jim_UnsetVariable(interp, argv[0], JIM_NONE);
+ return JIM_OK;
+ }
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (objPtr == NULL) {
+
+ return JIM_OK;
+ }
+
+ dictValuesObj = Jim_DictPairs(interp, objPtr, &len);
+ if (dictValuesObj == NULL) {
+
+ Jim_SetResultString(interp, "", -1);
+ return JIM_OK;
+ }
+
+
+ resultObj = Jim_NewDictObj(interp, NULL, 0);
+
+ for (i = 0; i < len; i += 2) {
+ if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+ Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
+ }
+ }
+
+ Jim_SetVariable(interp, argv[0], resultObj);
+ return JIM_OK;
+}
+
+static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int len = 0;
+
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ if (objPtr) {
+ len = Jim_DictSize(interp, objPtr);
+ if (len < 0) {
+
+ Jim_SetResultInt(interp, 0);
+ return JIM_OK;
+ }
+ }
+
+ Jim_SetResultInt(interp, len);
+
+ return JIM_OK;
+}
+
+static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ if (objPtr) {
+ return Jim_DictInfo(interp, objPtr);
+ }
+ Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL);
+ return JIM_ERR;
+}
+
+static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *listObj = argv[1];
+ Jim_Obj *dictObj;
+
+ len = Jim_ListLength(interp, listObj);
+ if (len % 2) {
+ Jim_SetResultString(interp, "list must have an even number of elements", -1);
+ return JIM_ERR;
+ }
+
+ dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
+ if (!dictObj) {
+
+ return Jim_SetVariable(interp, argv[0], listObj);
+ }
+ else if (Jim_DictSize(interp, dictObj) < 0) {
+ return JIM_ERR;
+ }
+
+ if (Jim_IsShared(dictObj)) {
+ dictObj = Jim_DuplicateObj(interp, dictObj);
+ }
+
+ for (i = 0; i < len; i += 2) {
+ Jim_Obj *nameObj;
+ Jim_Obj *valueObj;
+
+ Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
+ Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
+
+ Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
+ }
+ return Jim_SetVariable(interp, argv[0], dictObj);
+}
+
+static const jim_subcmd_type array_command_table[] = {
+ { "exists",
+ "arrayName",
+ array_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "get",
+ "arrayName ?pattern?",
+ array_cmd_get,
+ 1,
+ 2,
+
+ },
+ { "names",
+ "arrayName ?pattern?",
+ array_cmd_names,
+ 1,
+ 2,
+
+ },
+ { "set",
+ "arrayName list",
+ array_cmd_set,
+ 2,
+ 2,
+
+ },
+ { "size",
+ "arrayName",
+ array_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "stat",
+ "arrayName",
+ array_cmd_stat,
+ 1,
+ 1,
+
+ },
+ { "unset",
+ "arrayName ?pattern?",
+ array_cmd_unset,
+ 1,
+ 2,
+
+ },
+ { NULL
+ }
+};
+
+int Jim_arrayInit(Jim_Interp *interp)
+{
+ Jim_PackageProvideCheck(interp, "array");
+ Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+ return JIM_OK;
+}
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+{
+extern int Jim_bootstrapInit(Jim_Interp *);
+extern int Jim_aioInit(Jim_Interp *);
+extern int Jim_readdirInit(Jim_Interp *);
+extern int Jim_regexpInit(Jim_Interp *);
+extern int Jim_fileInit(Jim_Interp *);
+extern int Jim_globInit(Jim_Interp *);
+extern int Jim_execInit(Jim_Interp *);
+extern int Jim_clockInit(Jim_Interp *);
+extern int Jim_arrayInit(Jim_Interp *);
+extern int Jim_stdlibInit(Jim_Interp *);
+extern int Jim_tclcompatInit(Jim_Interp *);
+Jim_bootstrapInit(interp);
+Jim_aioInit(interp);
+Jim_readdirInit(interp);
+Jim_regexpInit(interp);
+Jim_fileInit(interp);
+Jim_globInit(interp);
+Jim_execInit(interp);
+Jim_clockInit(interp);
+Jim_arrayInit(interp);
+Jim_stdlibInit(interp);
+Jim_tclcompatInit(interp);
+return JIM_OK;
+}
+#ifndef JIM_TINY
+#define JIM_OPTIMIZATION
+#endif
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+#ifdef HAVE_EXECINFO_H
+#include
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include
+#endif
+
+
+#include
+
+
+
+
+
+#ifndef TCL_LIBRARY
+#define TCL_LIBRARY "."
+#endif
+#ifndef TCL_PLATFORM_OS
+#define TCL_PLATFORM_OS "unknown"
+#endif
+#ifndef TCL_PLATFORM_PLATFORM
+#define TCL_PLATFORM_PLATFORM "unknown"
+#endif
+#ifndef TCL_PLATFORM_PATH_SEPARATOR
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#endif
+
+
+
+
+
+
+
+#ifdef JIM_MAINTAINER
+#define JIM_DEBUG_COMMAND
+#define JIM_DEBUG_PANIC
+#endif
+
+
+
+#define JIM_INTEGER_SPACE 24
+
+#if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
+static const char *jim_tt_name(int type);
+#endif
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int fail_condition, const char *fmt, ...);
+#define JimPanic(X) JimPanicDump X
+#else
+#define JimPanic(X)
+#endif
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr);
+#define JIM_IF_OPTIM(X) X
+#else
+#define JIM_IF_OPTIM(X)
+#endif
+
+
+static char JimEmptyStringRep[] = "";
+
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
+ int flags);
+static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc,
+ Jim_Obj **resultObj, int flags);
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
+static int JimSign(jim_wide w);
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
+static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+#define JIM_DICT_SUGAR 100
+
+
+
+
+#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
+
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
+
+static int utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no)
+{
+ Jim_Obj *io = *iop;
+ Jim_IncrRefCount(no);
+ *iop = no;
+ return io;
+}
+
+#define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO)
+#define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0)
+
+
+#define JIM_CHARSET_SCAN 2
+#define JIM_CHARSET_GLOB 0
+
+static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags)
+{
+ int not = 0;
+ int pchar;
+ int match = 0;
+ int nocase = 0;
+ int n;
+
+ if (flags & JIM_NOCASE) {
+ nocase++;
+ c = utf8_upper(c);
+ }
+
+ if (flags & JIM_CHARSET_SCAN) {
+ if (*pattern == '^') {
+ not++;
+ pattern++;
+ plen--;
+ }
+
+
+ if (*pattern == ']') {
+ goto first;
+ }
+ }
+
+ while (plen && *pattern != ']') {
+
+ if (pattern[0] == '\\') {
+first:
+ n = utf8_tounicode_case(pattern, &pchar, nocase);
+ pattern += n;
+ plen -= n;
+ }
+ else {
+
+ int start;
+ int end;
+
+ n = utf8_tounicode_case(pattern, &start, nocase);
+ pattern += n;
+ plen -= n;
+ if (pattern[0] == '-' && plen > 1) {
+
+ n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase);
+ pattern += n;
+ plen -= n;
+
+
+ if ((c >= start && c <= end) || (c >= end && c <= start)) {
+ match = 1;
+ }
+ continue;
+ }
+ pchar = start;
+ }
+
+ if (pchar == c) {
+ match = 1;
+ }
+ }
+ if (not) {
+ match = !match;
+ }
+
+ return match ? pattern : NULL;
+}
+
+
+
+static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase)
+{
+ int c;
+ int pchar;
+ int n;
+ const char *p;
+ while (plen) {
+ switch (pattern[0]) {
+ case '*':
+ while (pattern[1] == '*' && plen) {
+ pattern++;
+ plen--;
+ }
+ pattern++;
+ plen--;
+ if (!plen) {
+ return 1;
+ }
+ while (slen) {
+
+ if (JimGlobMatch(pattern, plen, string, slen, nocase))
+ return 1;
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ }
+ return 0;
+
+ case '?':
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ break;
+
+ case '[': {
+ n = utf8_tounicode(string, &c);
+ string += n;
+ slen -= n;
+ p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0);
+ if (!p) {
+ return 0;
+ }
+ plen -= p - pattern;
+ pattern = p;
+
+ if (!plen) {
+
+ continue;
+ }
+ break;
+ }
+ case '\\':
+ if (pattern[1]) {
+ pattern++;
+ plen--;
+ }
+
+ default:
+ n = utf8_tounicode_case(string, &c, nocase);
+ string += n;
+ slen -= n;
+ utf8_tounicode_case(pattern, &pchar, nocase);
+ if (pchar != c) {
+ return 0;
+ }
+ break;
+ }
+ n = utf8_tounicode_case(pattern, &pchar, nocase);
+ pattern += n;
+ plen -= n;
+ if (!slen) {
+ while (*pattern == '*' && plen) {
+ pattern++;
+ plen--;
+ }
+ break;
+ }
+ }
+ if (!plen && !slen) {
+ return 1;
+ }
+ return 0;
+}
+
+static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase)
+{
+ int minlen = l1;
+ if (l2 < l1) {
+ minlen = l2;
+ }
+ while (minlen) {
+ int c1, c2;
+ s1 += utf8_tounicode_case(s1, &c1, nocase);
+ s2 += utf8_tounicode_case(s2, &c2, nocase);
+ if (c1 != c2) {
+ return JimSign(c1 - c2);
+ }
+ minlen--;
+ }
+
+ if (l1 < l2) {
+ return -1;
+ }
+ if (l1 > l2) {
+ return 1;
+ }
+ return 0;
+}
+
+static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
+{
+ int i;
+ int l1bytelen;
+
+ if (!l1 || !l2 || l1 > l2) {
+ return -1;
+ }
+ if (idx < 0)
+ idx = 0;
+ s2 += utf8_index(s2, idx);
+
+ l1bytelen = utf8_index(s1, l1);
+
+ for (i = idx; i <= l2 - l1; i++) {
+ int c;
+ if (memcmp(s2, s1, l1bytelen) == 0) {
+ return i;
+ }
+ s2 += utf8_tounicode(s2, &c);
+ }
+ return -1;
+}
+
+static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
+{
+ const char *p;
+
+ if (!l1 || !l2 || l1 > l2)
+ return -1;
+
+
+ for (p = s2 + l2 - 1; p != s2 - 1; p--) {
+ if (*p == *s1 && memcmp(s1, p, l1) == 0) {
+ return p - s2;
+ }
+ }
+ return -1;
+}
+
+#ifdef JIM_UTF8
+static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
+{
+ int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
+ if (n > 0) {
+ n = utf8_strlen(s2, n);
+ }
+ return n;
+}
+#endif
+
+static int JimCheckConversion(const char *str, const char *endptr)
+{
+ if (str[0] == '\0' || str == endptr) {
+ return JIM_ERR;
+ }
+
+ if (endptr[0] != '\0') {
+ while (*endptr) {
+ if (!isspace(UCHAR(*endptr))) {
+ return JIM_ERR;
+ }
+ endptr++;
+ }
+ }
+ return JIM_OK;
+}
+
+static int JimNumberBase(const char *str, int *base, int *sign)
+{
+ int i = 0;
+
+ *base = 0;
+
+ while (isspace(UCHAR(str[i]))) {
+ i++;
+ }
+
+ if (str[i] == '-') {
+ *sign = -1;
+ i++;
+ }
+ else {
+ if (str[i] == '+') {
+ i++;
+ }
+ *sign = 1;
+ }
+
+ if (str[i] != '0') {
+
+ return 0;
+ }
+
+
+ switch (str[i + 1]) {
+ case 'x': case 'X': *base = 16; break;
+ case 'o': case 'O': *base = 8; break;
+ case 'b': case 'B': *base = 2; break;
+ case 'd': case 'D': *base = 10; break;
+ default: return 0;
+ }
+ i += 2;
+
+ if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
+
+ return i;
+ }
+
+ *base = 0;
+ return 0;
+}
+
+static long jim_strtol(const char *str, char **endptr)
+{
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 0) {
+ long value = strtol(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtol(str, endptr, 10);
+}
+
+
+static jim_wide jim_strtoull(const char *str, char **endptr)
+{
+#ifdef HAVE_LONG_LONG
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 0) {
+ jim_wide value = strtoull(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtoull(str, endptr, 10);
+#else
+ return (unsigned long)jim_strtol(str, endptr);
+#endif
+}
+
+int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
+{
+ char *endptr;
+
+ if (base) {
+ *widePtr = strtoull(str, &endptr, base);
+ }
+ else {
+ *widePtr = jim_strtoull(str, &endptr);
+ }
+
+ return JimCheckConversion(str, endptr);
+}
+
+int Jim_StringToDouble(const char *str, double *doublePtr)
+{
+ char *endptr;
+
+
+ errno = 0;
+
+ *doublePtr = strtod(str, &endptr);
+
+ return JimCheckConversion(str, endptr);
+}
+
+static jim_wide JimPowWide(jim_wide b, jim_wide e)
+{
+ jim_wide res = 1;
+
+
+ if (b == 1) {
+
+ return 1;
+ }
+ if (e < 0) {
+ if (b != -1) {
+ return 0;
+ }
+ e = -e;
+ }
+ while (e)
+ {
+ if (e & 1) {
+ res *= b;
+ }
+ e >>= 1;
+ b *= b;
+ }
+ return res;
+}
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int condition, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!condition) {
+ return;
+ }
+
+ va_start(ap, fmt);
+
+ fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n\n");
+ va_end(ap);
+
+#if defined(HAVE_BACKTRACE)
+ {
+ void *array[40];
+ int size, i;
+ char **strings;
+
+ size = backtrace(array, 40);
+ strings = backtrace_symbols(array, size);
+ for (i = 0; i < size; i++)
+ fprintf(stderr, "[backtrace] %s\n", strings[i]);
+ fprintf(stderr, "[backtrace] Include the above lines and the output\n");
+ fprintf(stderr, "[backtrace] of 'nm ' in the bug report.\n");
+ }
+#endif
+
+ exit(1);
+}
+#endif
+
+
+void *JimDefaultAllocator(void *ptr, size_t size)
+{
+ if (size == 0) {
+ free(ptr);
+ return NULL;
+ }
+ else if (ptr) {
+ return realloc(ptr, size);
+ }
+ else {
+ return malloc(size);
+ }
+}
+
+void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;
+
+char *Jim_StrDup(const char *s)
+{
+ return Jim_StrDupLen(s, strlen(s));
+}
+
+char *Jim_StrDupLen(const char *s, int l)
+{
+ char *copy = Jim_Alloc(l + 1);
+
+ memcpy(copy, s, l);
+ copy[l] = 0;
+ return copy;
+}
+
+
+jim_wide Jim_GetTimeUsec(unsigned type)
+{
+ long long now;
+ struct timeval tv;
+
+#if defined(HAVE_CLOCK_GETTIME)
+ struct timespec ts;
+
+ if (clock_gettime(type, &ts) == 0) {
+ now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+ }
+ else
+#endif
+ {
+ gettimeofday(&tv, NULL);
+
+ now = tv.tv_sec * 1000000LL + tv.tv_usec;
+ }
+
+ return now;
+}
+
+
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
+static unsigned int JimHashTableNextPower(unsigned int size);
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
+
+
+
+
+unsigned int Jim_IntHashFunction(unsigned int key)
+{
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+}
+
+
+unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
+{
+ unsigned result = 0;
+ string += length;
+ while (length--) {
+ result += (result << 3) + (unsigned char)(*--string);
+ }
+ return result;
+}
+
+
+
+static void JimResetHashTable(Jim_HashTable *ht)
+{
+ ht->table = NULL;
+ ht->size = 0;
+ ht->sizemask = 0;
+ ht->used = 0;
+ ht->collisions = 0;
+#ifdef JIM_RANDOMISE_HASH
+ ht->uniq = (rand() ^ time(NULL) ^ clock());
+#else
+ ht->uniq = 0;
+#endif
+}
+
+static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
+{
+ iter->ht = ht;
+ iter->index = -1;
+ iter->entry = NULL;
+ iter->nextEntry = NULL;
+}
+
+
+int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
+{
+ JimResetHashTable(ht);
+ ht->type = type;
+ ht->privdata = privDataPtr;
+ return JIM_OK;
+}
+
+
+void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
+{
+ Jim_HashTable n;
+ unsigned int realsize = JimHashTableNextPower(size), i;
+
+ if (size <= ht->used)
+ return;
+
+ Jim_InitHashTable(&n, ht->type, ht->privdata);
+ n.size = realsize;
+ n.sizemask = realsize - 1;
+ n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
+
+ n.uniq = ht->uniq;
+
+
+ memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
+
+ n.used = ht->used;
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ if (ht->table[i] == NULL)
+ continue;
+
+
+ he = ht->table[i];
+ while (he) {
+ unsigned int h;
+
+ nextHe = he->next;
+
+ h = Jim_HashKey(ht, he->key) & n.sizemask;
+ he->next = n.table[h];
+ n.table[h] = he;
+ ht->used--;
+
+ he = nextHe;
+ }
+ }
+ assert(ht->used == 0);
+ Jim_Free(ht->table);
+
+
+ *ht = n;
+}
+
+int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
+ if (entry == NULL)
+ return JIM_ERR;
+
+
+ Jim_SetHashKey(ht, entry, key);
+ Jim_SetHashVal(ht, entry, val);
+ return JIM_OK;
+}
+
+
+int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ int existed;
+ Jim_HashEntry *entry;
+
+ entry = JimInsertHashEntry(ht, key, 1);
+ if (entry->key) {
+ if (ht->type->valDestructor && ht->type->valDup) {
+ void *newval = ht->type->valDup(ht->privdata, val);
+ ht->type->valDestructor(ht->privdata, entry->u.val);
+ entry->u.val = newval;
+ }
+ else {
+ Jim_FreeEntryVal(ht, entry);
+ Jim_SetHashVal(ht, entry, val);
+ }
+ existed = 1;
+ }
+ else {
+
+ Jim_SetHashKey(ht, entry, key);
+ Jim_SetHashVal(ht, entry, val);
+ existed = 0;
+ }
+
+ return existed;
+}
+
+int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
+{
+ if (ht->used) {
+ unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
+ Jim_HashEntry *prevHe = NULL;
+ Jim_HashEntry *he = ht->table[h];
+
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key)) {
+
+ if (prevHe)
+ prevHe->next = he->next;
+ else
+ ht->table[h] = he->next;
+ ht->used--;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ return JIM_OK;
+ }
+ prevHe = he;
+ he = he->next;
+ }
+ }
+
+ return JIM_ERR;
+}
+
+void Jim_ClearHashTable(Jim_HashTable *ht)
+{
+ unsigned int i;
+
+
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ he = ht->table[i];
+ while (he) {
+ nextHe = he->next;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ ht->used--;
+ he = nextHe;
+ }
+ ht->table[i] = NULL;
+ }
+}
+
+int Jim_FreeHashTable(Jim_HashTable *ht)
+{
+ Jim_ClearHashTable(ht);
+
+ Jim_Free(ht->table);
+
+ JimResetHashTable(ht);
+ return JIM_OK;
+}
+
+Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
+{
+ Jim_HashEntry *he;
+ unsigned int h;
+
+ if (ht->used == 0)
+ return NULL;
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return he;
+ he = he->next;
+ }
+ return NULL;
+}
+
+Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
+{
+ Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
+ JimInitHashTableIterator(ht, iter);
+ return iter;
+}
+
+Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
+{
+ while (1) {
+ if (iter->entry == NULL) {
+ iter->index++;
+ if (iter->index >= (signed)iter->ht->size)
+ break;
+ iter->entry = iter->ht->table[iter->index];
+ }
+ else {
+ iter->entry = iter->nextEntry;
+ }
+ if (iter->entry) {
+ iter->nextEntry = iter->entry->next;
+ return iter->entry;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
+{
+ if (ht->size == 0)
+ Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
+ if (ht->size == ht->used)
+ Jim_ExpandHashTable(ht, ht->size * 2);
+}
+
+
+static unsigned int JimHashTableNextPower(unsigned int size)
+{
+ unsigned int i = JIM_HT_INITIAL_SIZE;
+
+ if (size >= 2147483648U)
+ return 2147483648U;
+ while (1) {
+ if (i >= size)
+ return i;
+ i *= 2;
+ }
+}
+
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
+{
+ unsigned int h;
+ Jim_HashEntry *he;
+
+
+ JimExpandHashTableIfNeeded(ht);
+
+
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return replace ? he : NULL;
+ he = he->next;
+ }
+
+
+ he = Jim_Alloc(sizeof(*he));
+ he->next = ht->table[h];
+ ht->table[h] = he;
+ ht->used++;
+ he->key = NULL;
+
+ return he;
+}
+
+
+
+static unsigned int JimStringCopyHTHashFunction(const void *key)
+{
+ return Jim_GenHashFunction(key, strlen(key));
+}
+
+static void *JimStringCopyHTDup(void *privdata, const void *key)
+{
+ return Jim_StrDup(key);
+}
+
+static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return strcmp(key1, key2) == 0;
+}
+
+static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
+{
+ Jim_Free(key);
+}
+
+static const Jim_HashTableType JimPackageHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ NULL
+};
+
+typedef struct AssocDataValue
+{
+ Jim_InterpDeleteProc *delProc;
+ void *data;
+} AssocDataValue;
+
+static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
+{
+ AssocDataValue *assocPtr = (AssocDataValue *) data;
+
+ if (assocPtr->delProc != NULL)
+ assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
+ Jim_Free(data);
+}
+
+static const Jim_HashTableType JimAssocDataHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ JimAssocDataHashTableValueDestructor
+};
+
+void Jim_InitStack(Jim_Stack *stack)
+{
+ stack->len = 0;
+ stack->maxlen = 0;
+ stack->vector = NULL;
+}
+
+void Jim_FreeStack(Jim_Stack *stack)
+{
+ Jim_Free(stack->vector);
+}
+
+int Jim_StackLen(Jim_Stack *stack)
+{
+ return stack->len;
+}
+
+void Jim_StackPush(Jim_Stack *stack, void *element)
+{
+ int neededLen = stack->len + 1;
+
+ if (neededLen > stack->maxlen) {
+ stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
+ stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
+ }
+ stack->vector[stack->len] = element;
+ stack->len++;
+}
+
+void *Jim_StackPop(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ stack->len--;
+ return stack->vector[stack->len];
+}
+
+void *Jim_StackPeek(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ return stack->vector[stack->len - 1];
+}
+
+void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
+{
+ int i;
+
+ for (i = 0; i < stack->len; i++)
+ freeFunc(stack->vector[i]);
+}
+
+
+
+#define JIM_TT_NONE 0
+#define JIM_TT_STR 1
+#define JIM_TT_ESC 2
+#define JIM_TT_VAR 3
+#define JIM_TT_DICTSUGAR 4
+#define JIM_TT_CMD 5
+
+#define JIM_TT_SEP 6
+#define JIM_TT_EOL 7
+#define JIM_TT_EOF 8
+
+#define JIM_TT_LINE 9
+#define JIM_TT_WORD 10
+
+
+#define JIM_TT_SUBEXPR_START 11
+#define JIM_TT_SUBEXPR_END 12
+#define JIM_TT_SUBEXPR_COMMA 13
+#define JIM_TT_EXPR_INT 14
+#define JIM_TT_EXPR_DOUBLE 15
+#define JIM_TT_EXPR_BOOLEAN 16
+
+#define JIM_TT_EXPRSUGAR 17
+
+
+#define JIM_TT_EXPR_OP 20
+
+#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
+
+#define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
+
+#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
+
+struct JimParseMissing {
+ int ch;
+ int line;
+};
+
+struct JimParserCtx
+{
+ const char *p;
+ int len;
+ int linenr;
+ const char *tstart;
+ const char *tend;
+ int tline;
+ int tt;
+ int eof;
+ int inquote;
+ int comment;
+ struct JimParseMissing missing;
+ const char *errmsg;
+};
+
+static int JimParseScript(struct JimParserCtx *pc);
+static int JimParseSep(struct JimParserCtx *pc);
+static int JimParseEol(struct JimParserCtx *pc);
+static int JimParseCmd(struct JimParserCtx *pc);
+static int JimParseQuote(struct JimParserCtx *pc);
+static int JimParseVar(struct JimParserCtx *pc);
+static int JimParseBrace(struct JimParserCtx *pc);
+static int JimParseStr(struct JimParserCtx *pc);
+static int JimParseComment(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static int JimParseSubQuote(struct JimParserCtx *pc);
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
+
+static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
+{
+ pc->p = prg;
+ pc->len = len;
+ pc->tstart = NULL;
+ pc->tend = NULL;
+ pc->tline = 0;
+ pc->tt = JIM_TT_NONE;
+ pc->eof = 0;
+ pc->inquote = 0;
+ pc->linenr = linenr;
+ pc->comment = 1;
+ pc->missing.ch = ' ';
+ pc->missing.line = linenr;
+}
+
+static int JimParseScript(struct JimParserCtx *pc)
+{
+ while (1) {
+ if (!pc->len) {
+ pc->tstart = pc->p;
+ pc->tend = pc->p - 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ if (pc->inquote) {
+ pc->missing.ch = '"';
+ }
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '\\':
+ if (*(pc->p + 1) == '\n' && !pc->inquote) {
+ return JimParseSep(pc);
+ }
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\f':
+ if (!pc->inquote)
+ return JimParseSep(pc);
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case '\n':
+ case ';':
+ pc->comment = 1;
+ if (!pc->inquote)
+ return JimParseEol(pc);
+ return JimParseStr(pc);
+ case '[':
+ pc->comment = 0;
+ return JimParseCmd(pc);
+ case '$':
+ pc->comment = 0;
+ if (JimParseVar(pc) == JIM_ERR) {
+
+ pc->tstart = pc->tend = pc->p++;
+ pc->len--;
+ pc->tt = JIM_TT_ESC;
+ }
+ return JIM_OK;
+ case '#':
+ if (pc->comment) {
+ JimParseComment(pc);
+ continue;
+ }
+ return JimParseStr(pc);
+ default:
+ pc->comment = 0;
+ return JimParseStr(pc);
+ }
+ return JIM_OK;
+ }
+}
+
+static int JimParseSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ break;
+ }
+ if (*pc->p == '\\') {
+ pc->p++;
+ pc->len--;
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseEol(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
+ if (*pc->p == '\n')
+ pc->linenr++;
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EOL;
+ return JIM_OK;
+}
+
+
+static void JimParseSubBrace(struct JimParserCtx *pc)
+{
+ int level = 1;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '{';
+ pc->missing.line = pc->tline;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseSubQuote(struct JimParserCtx *pc)
+{
+ int tt = JIM_TT_STR;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ tt = JIM_TT_ESC;
+ }
+ break;
+
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return tt;
+
+ case '[':
+ JimParseSubCmd(pc);
+ tt = JIM_TT_ESC;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+
+ case '$':
+ tt = JIM_TT_ESC;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '"';
+ pc->missing.line = line;
+ pc->tend = pc->p - 1;
+ return tt;
+}
+
+static void JimParseSubCmd(struct JimParserCtx *pc)
+{
+ int level = 1;
+ int startofword = 1;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '[':
+ level++;
+ break;
+
+ case ']':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '"':
+ if (startofword) {
+ JimParseSubQuote(pc);
+ if (pc->missing.ch == '"') {
+ return;
+ }
+ continue;
+ }
+ break;
+
+ case '{':
+ JimParseSubBrace(pc);
+ startofword = 0;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ startofword = isspace(UCHAR(*pc->p));
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing.ch = '[';
+ pc->missing.line = line;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseBrace(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+ JimParseSubBrace(pc);
+ return JIM_OK;
+}
+
+static int JimParseCmd(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_CMD;
+ JimParseSubCmd(pc);
+ return JIM_OK;
+}
+
+static int JimParseQuote(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JimParseSubQuote(pc);
+ return JIM_OK;
+}
+
+static int JimParseVar(struct JimParserCtx *pc)
+{
+
+ pc->p++;
+ pc->len--;
+
+#ifdef EXPRSUGAR_BRACKET
+ if (*pc->p == '[') {
+
+ JimParseCmd(pc);
+ pc->tt = JIM_TT_EXPRSUGAR;
+ return JIM_OK;
+ }
+#endif
+
+ pc->tstart = pc->p;
+ pc->tt = JIM_TT_VAR;
+ pc->tline = pc->linenr;
+
+ if (*pc->p == '{') {
+ pc->tstart = ++pc->p;
+ pc->len--;
+
+ while (pc->len && *pc->p != '}') {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ if (pc->len) {
+ pc->p++;
+ pc->len--;
+ }
+ }
+ else {
+ while (1) {
+
+ if (pc->p[0] == ':' && pc->p[1] == ':') {
+ while (*pc->p == ':') {
+ pc->p++;
+ pc->len--;
+ }
+ continue;
+ }
+ if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
+ pc->p++;
+ pc->len--;
+ continue;
+ }
+ break;
+ }
+
+ if (*pc->p == '(') {
+ int count = 1;
+ const char *paren = NULL;
+
+ pc->tt = JIM_TT_DICTSUGAR;
+
+ while (count && pc->len) {
+ pc->p++;
+ pc->len--;
+ if (*pc->p == '\\' && pc->len >= 1) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (*pc->p == '(') {
+ count++;
+ }
+ else if (*pc->p == ')') {
+ paren = pc->p;
+ count--;
+ }
+ }
+ if (count == 0) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (paren) {
+
+ paren++;
+ pc->len += (pc->p - paren);
+ pc->p = paren;
+ }
+#ifndef EXPRSUGAR_BRACKET
+ if (*pc->tstart == '(') {
+ pc->tt = JIM_TT_EXPRSUGAR;
+ }
+#endif
+ }
+ pc->tend = pc->p - 1;
+ }
+ if (pc->tstart == pc->p) {
+ pc->p--;
+ pc->len++;
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int JimParseStr(struct JimParserCtx *pc)
+{
+ if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
+ pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
+
+ if (*pc->p == '{') {
+ return JimParseBrace(pc);
+ }
+ if (*pc->p == '"') {
+ pc->inquote = 1;
+ pc->p++;
+ pc->len--;
+
+ pc->missing.line = pc->tline;
+ }
+ }
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (1) {
+ if (pc->len == 0) {
+ if (pc->inquote) {
+ pc->missing.ch = '"';
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ switch (*pc->p) {
+ case '\\':
+ if (!pc->inquote && *(pc->p + 1) == '\n') {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ if (pc->len >= 2) {
+ if (*(pc->p + 1) == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ else if (pc->len == 1) {
+
+ pc->missing.ch = '\\';
+ }
+ break;
+ case '(':
+
+ if (pc->len > 1 && pc->p[1] != '$') {
+ break;
+ }
+
+ case ')':
+
+ if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
+ if (pc->p == pc->tstart) {
+
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ break;
+
+ case '$':
+ case '[':
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ case ';':
+ if (!pc->inquote) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ else if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ break;
+ case '"':
+ if (pc->inquote) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ pc->len--;
+ pc->inquote = 0;
+ return JIM_OK;
+ }
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+static int JimParseComment(struct JimParserCtx *pc)
+{
+ while (*pc->p) {
+ if (*pc->p == '\\') {
+ pc->p++;
+ pc->len--;
+ if (pc->len == 0) {
+ pc->missing.ch = '\\';
+ return JIM_OK;
+ }
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ }
+ else if (*pc->p == '\n') {
+ pc->p++;
+ pc->len--;
+ pc->linenr++;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+
+static int xdigitval(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int odigitval(int c)
+{
+ if (c >= '0' && c <= '7')
+ return c - '0';
+ return -1;
+}
+
+static int JimEscape(char *dest, const char *s, int slen)
+{
+ char *p = dest;
+ int i, len;
+
+ for (i = 0; i < slen; i++) {
+ switch (s[i]) {
+ case '\\':
+ switch (s[i + 1]) {
+ case 'a':
+ *p++ = 0x7;
+ i++;
+ break;
+ case 'b':
+ *p++ = 0x8;
+ i++;
+ break;
+ case 'f':
+ *p++ = 0xc;
+ i++;
+ break;
+ case 'n':
+ *p++ = 0xa;
+ i++;
+ break;
+ case 'r':
+ *p++ = 0xd;
+ i++;
+ break;
+ case 't':
+ *p++ = 0x9;
+ i++;
+ break;
+ case 'u':
+ case 'U':
+ case 'x':
+ {
+ unsigned val = 0;
+ int k;
+ int maxchars = 2;
+
+ i++;
+
+ if (s[i] == 'U') {
+ maxchars = 8;
+ }
+ else if (s[i] == 'u') {
+ if (s[i + 1] == '{') {
+ maxchars = 6;
+ i++;
+ }
+ else {
+ maxchars = 4;
+ }
+ }
+
+ for (k = 0; k < maxchars; k++) {
+ int c = xdigitval(s[i + k + 1]);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+
+ if (s[i] == '{') {
+ if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
+
+ i--;
+ k = 0;
+ }
+ else {
+
+ k++;
+ }
+ }
+ if (k) {
+
+ if (s[i] == 'x') {
+ *p++ = val;
+ }
+ else {
+ p += utf8_fromunicode(p, val);
+ }
+ i += k;
+ break;
+ }
+
+ *p++ = s[i];
+ }
+ break;
+ case 'v':
+ *p++ = 0xb;
+ i++;
+ break;
+ case '\0':
+ *p++ = '\\';
+ i++;
+ break;
+ case '\n':
+
+ *p++ = ' ';
+ do {
+ i++;
+ } while (s[i + 1] == ' ' || s[i + 1] == '\t');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+
+ {
+ int val = 0;
+ int c = odigitval(s[i + 1]);
+
+ val = c;
+ c = odigitval(s[i + 2]);
+ if (c == -1) {
+ *p++ = val;
+ i++;
+ break;
+ }
+ val = (val * 8) + c;
+ c = odigitval(s[i + 3]);
+ if (c == -1) {
+ *p++ = val;
+ i += 2;
+ break;
+ }
+ val = (val * 8) + c;
+ *p++ = val;
+ i += 3;
+ }
+ break;
+ default:
+ *p++ = s[i + 1];
+ i++;
+ break;
+ }
+ break;
+ default:
+ *p++ = s[i];
+ break;
+ }
+ }
+ len = p - dest;
+ *p = '\0';
+ return len;
+}
+
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
+{
+ const char *start, *end;
+ char *token;
+ int len;
+
+ start = pc->tstart;
+ end = pc->tend;
+ len = (end - start) + 1;
+ if (len < 0) {
+ len = 0;
+ }
+ token = Jim_Alloc(len + 1);
+ if (pc->tt != JIM_TT_ESC) {
+
+ memcpy(token, start, len);
+ token[len] = '\0';
+ }
+ else {
+
+ len = JimEscape(token, start, len);
+ }
+
+ return Jim_NewStringObjNoAlloc(interp, token, len);
+}
+
+static int JimParseListSep(struct JimParserCtx *pc);
+static int JimParseListStr(struct JimParserCtx *pc);
+static int JimParseListQuote(struct JimParserCtx *pc);
+
+static int JimParseList(struct JimParserCtx *pc)
+{
+ if (isspace(UCHAR(*pc->p))) {
+ return JimParseListSep(pc);
+ }
+ switch (*pc->p) {
+ case '"':
+ return JimParseListQuote(pc);
+
+ case '{':
+ return JimParseBrace(pc);
+
+ default:
+ if (pc->len) {
+ return JimParseListStr(pc);
+ }
+ break;
+ }
+
+ pc->tstart = pc->tend = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+}
+
+static int JimParseListSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p))) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseListQuote(struct JimParserCtx *pc)
+{
+ pc->p++;
+ pc->len--;
+
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ pc->tt = JIM_TT_ESC;
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->p++;
+ break;
+ case '\n':
+ pc->linenr++;
+ break;
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return JIM_OK;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+static int JimParseListStr(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ if (isspace(UCHAR(*pc->p))) {
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+ }
+ if (*pc->p == '\\') {
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+
+
+Jim_Obj *Jim_NewObj(Jim_Interp *interp)
+{
+ Jim_Obj *objPtr;
+
+
+ if (interp->freeList != NULL) {
+
+ objPtr = interp->freeList;
+ interp->freeList = objPtr->nextObjPtr;
+ }
+ else {
+
+ objPtr = Jim_Alloc(sizeof(*objPtr));
+ }
+
+ objPtr->refCount = 0;
+
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->liveList;
+ if (interp->liveList)
+ interp->liveList->prevObjPtr = objPtr;
+ interp->liveList = objPtr;
+
+ return objPtr;
+}
+
+void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+
+ JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+ objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : ""));
+
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+
+ if (objPtr->prevObjPtr)
+ objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
+ if (objPtr->nextObjPtr)
+ objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
+ if (interp->liveList == objPtr)
+ interp->liveList = objPtr->nextObjPtr;
+#ifdef JIM_DISABLE_OBJECT_POOL
+ Jim_Free(objPtr);
+#else
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->freeList;
+ if (interp->freeList)
+ interp->freeList->prevObjPtr = objPtr;
+ interp->freeList = objPtr;
+ objPtr->refCount = -1;
+#endif
+}
+
+
+void Jim_InvalidateStringRep(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+ objPtr->bytes = NULL;
+}
+
+
+Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *dupPtr;
+
+ dupPtr = Jim_NewObj(interp);
+ if (objPtr->bytes == NULL) {
+
+ dupPtr->bytes = NULL;
+ }
+ else if (objPtr->length == 0) {
+ dupPtr->bytes = JimEmptyStringRep;
+ dupPtr->length = 0;
+ dupPtr->typePtr = NULL;
+ return dupPtr;
+ }
+ else {
+ dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
+ dupPtr->length = objPtr->length;
+
+ memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
+ }
+
+
+ dupPtr->typePtr = objPtr->typePtr;
+ if (objPtr->typePtr != NULL) {
+ if (objPtr->typePtr->dupIntRepProc == NULL) {
+ dupPtr->internalRep = objPtr->internalRep;
+ }
+ else {
+
+ objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
+ }
+ }
+ return dupPtr;
+}
+
+const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+ if (lenPtr)
+ *lenPtr = objPtr->length;
+ return objPtr->bytes;
+}
+
+
+int Jim_Length(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ Jim_GetString(objPtr, NULL);
+ }
+ return objPtr->length;
+}
+
+
+const char *Jim_String(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ Jim_GetString(objPtr, NULL);
+ }
+ return objPtr->bytes;
+}
+
+static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
+{
+ objPtr->bytes = Jim_StrDup(str);
+ objPtr->length = strlen(str);
+}
+
+static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType dictSubstObjType = {
+ "dict-substitution",
+ FreeDictSubstInternalRep,
+ DupDictSubstInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType interpolatedObjType = {
+ "interpolated",
+ FreeInterpolatedInternalRep,
+ DupInterpolatedInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+
+ dupPtr->internalRep = srcPtr->internalRep;
+
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType stringObjType = {
+ "string",
+ NULL,
+ DupStringInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.strValue.maxLength = srcPtr->length;
+ dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
+}
+
+static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &stringObjType) {
+
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = objPtr->length;
+
+ objPtr->internalRep.strValue.charLength = -1;
+ }
+ return JIM_OK;
+}
+
+int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef JIM_UTF8
+ SetStringFromAny(interp, objPtr);
+
+ if (objPtr->internalRep.strValue.charLength < 0) {
+ objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
+ }
+ return objPtr->internalRep.strValue.charLength;
+#else
+ return Jim_Length(objPtr);
+#endif
+}
+
+
+Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+
+ if (len == -1)
+ len = strlen(s);
+
+ if (len == 0) {
+ objPtr->bytes = JimEmptyStringRep;
+ }
+ else {
+ objPtr->bytes = Jim_StrDupLen(s, len);
+ }
+ objPtr->length = len;
+
+
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+
+Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
+{
+#ifdef JIM_UTF8
+
+ int bytelen = utf8_index(s, charlen);
+
+ Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
+
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = bytelen;
+ objPtr->internalRep.strValue.charLength = charlen;
+
+ return objPtr;
+#else
+ return Jim_NewStringObj(interp, s, charlen);
+#endif
+}
+
+Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+ objPtr->bytes = s;
+ objPtr->length = (len == -1) ? strlen(s) : len;
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
+{
+ int needlen;
+
+ if (len == -1)
+ len = strlen(str);
+ needlen = objPtr->length + len;
+ if (objPtr->internalRep.strValue.maxLength < needlen ||
+ objPtr->internalRep.strValue.maxLength == 0) {
+ needlen *= 2;
+
+ if (needlen < 7) {
+ needlen = 7;
+ }
+ if (objPtr->bytes == JimEmptyStringRep) {
+ objPtr->bytes = Jim_Alloc(needlen + 1);
+ }
+ else {
+ objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
+ }
+ objPtr->internalRep.strValue.maxLength = needlen;
+ }
+ memcpy(objPtr->bytes + objPtr->length, str, len);
+ objPtr->bytes[objPtr->length + len] = '\0';
+
+ if (objPtr->internalRep.strValue.charLength >= 0) {
+
+ objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
+ }
+ objPtr->length += len;
+}
+
+void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
+ SetStringFromAny(interp, objPtr);
+ StringAppendString(objPtr, str, len);
+}
+
+void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
+{
+ int len;
+ const char *str = Jim_GetString(appendObjPtr, &len);
+ Jim_AppendString(interp, objPtr, str, len);
+}
+
+void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
+{
+ va_list ap;
+
+ SetStringFromAny(interp, objPtr);
+ va_start(ap, objPtr);
+ while (1) {
+ const char *s = va_arg(ap, const char *);
+
+ if (s == NULL)
+ break;
+ Jim_AppendString(interp, objPtr, s, -1);
+ }
+ va_end(ap);
+}
+
+int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
+{
+ if (aObjPtr == bObjPtr) {
+ return 1;
+ }
+ else {
+ int Alen, Blen;
+ const char *sA = Jim_GetString(aObjPtr, &Alen);
+ const char *sB = Jim_GetString(bObjPtr, &Blen);
+
+ return Alen == Blen && memcmp(sA, sB, Alen) == 0;
+ }
+}
+
+int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
+{
+ int plen, slen;
+ const char *pattern = Jim_GetString(patternObjPtr, &plen);
+ const char *string = Jim_GetString(objPtr, &slen);
+ return JimGlobMatch(pattern, plen, string, slen, nocase);
+}
+
+int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+ const char *s1 = Jim_String(firstObjPtr);
+ int l1 = Jim_Utf8Length(interp, firstObjPtr);
+ const char *s2 = Jim_String(secondObjPtr);
+ int l2 = Jim_Utf8Length(interp, secondObjPtr);
+ return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
+}
+
+static int JimRelToAbsIndex(int len, int idx)
+{
+ if (idx < 0 && idx > -INT_MAX)
+ return len + idx;
+ return idx;
+}
+
+static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
+{
+ int rangeLen;
+
+ if (*firstPtr > *lastPtr) {
+ rangeLen = 0;
+ }
+ else {
+ rangeLen = *lastPtr - *firstPtr + 1;
+ if (rangeLen) {
+ if (*firstPtr < 0) {
+ rangeLen += *firstPtr;
+ *firstPtr = 0;
+ }
+ if (*lastPtr >= len) {
+ rangeLen -= (*lastPtr - (len - 1));
+ *lastPtr = len - 1;
+ }
+ }
+ }
+ if (rangeLen < 0)
+ rangeLen = 0;
+
+ *rangeLenPtr = rangeLen;
+}
+
+static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
+ int len, int *first, int *last, int *range)
+{
+ if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ *first = JimRelToAbsIndex(len, *first);
+ *last = JimRelToAbsIndex(len, *last);
+ JimRelToAbsRange(len, first, last, range);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ const char *str;
+ int rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == bytelen) {
+ return strObjPtr;
+ }
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+}
+
+Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+#ifdef JIM_UTF8
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == len) {
+ return strObjPtr;
+ }
+ if (len == bytelen) {
+
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+ }
+ return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
+#else
+ return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
+#endif
+}
+
+Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
+{
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ Jim_Obj *objPtr;
+
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (last < first) {
+ return strObjPtr;
+ }
+
+ str = Jim_String(strObjPtr);
+
+
+ objPtr = Jim_NewStringObjUtf8(interp, str, first);
+
+
+ if (newStrObj) {
+ Jim_AppendObj(interp, objPtr, newStrObj);
+ }
+
+
+ Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
+
+ return objPtr;
+}
+
+static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
+{
+ while (*str) {
+ int c;
+ str += utf8_tounicode(str, &c);
+ dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
+ }
+ *dest = 0;
+}
+
+static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ int len;
+ const char *str;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 0);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ const char *str;
+ int len;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 1);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf, *p;
+ int len;
+ int c;
+ const char *str;
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = p = Jim_Alloc(len + 1);
+
+ str += utf8_tounicode(str, &c);
+ p += utf8_getchars(p, utf8_title(c));
+
+ JimStrCopyUpperLower(p, str, 0);
+
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static const char *utf8_memchr(const char *str, int len, int c)
+{
+#ifdef JIM_UTF8
+ while (len) {
+ int sc;
+ int n = utf8_tounicode(str, &sc);
+ if (sc == c) {
+ return str;
+ }
+ str += n;
+ len -= n;
+ }
+ return NULL;
+#else
+ return memchr(str, c, len);
+#endif
+}
+
+static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
+{
+ while (len) {
+ int c;
+ int n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+
+ break;
+ }
+ str += n;
+ len -= n;
+ }
+ return str;
+}
+
+static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
+{
+ str += len;
+
+ while (len) {
+ int c;
+ int n = utf8_prev_len(str, len);
+
+ len -= n;
+ str -= n;
+
+ n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+ return str + n;
+ }
+ }
+
+ return NULL;
+}
+
+static const char default_trim_chars[] = " \t\n\r";
+
+static int default_trim_chars_len = sizeof(default_trim_chars);
+
+static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *str = Jim_GetString(strObjPtr, &len);
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *newstr;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
+ if (newstr == str) {
+ return strObjPtr;
+ }
+
+ return Jim_NewStringObj(interp, newstr, len - (newstr - str));
+}
+
+static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *nontrim;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ SetStringFromAny(interp, strObjPtr);
+
+ len = Jim_Length(strObjPtr);
+ nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
+
+ if (nontrim == NULL) {
+
+ return Jim_NewEmptyStringObj(interp);
+ }
+ if (nontrim == strObjPtr->bytes + len) {
+
+ return strObjPtr;
+ }
+
+ if (Jim_IsShared(strObjPtr)) {
+ strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
+ }
+ else {
+
+ strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
+ strObjPtr->length = (nontrim - strObjPtr->bytes);
+ }
+
+ return strObjPtr;
+}
+
+static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+
+ Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
+
+
+ strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
+
+
+ if (objPtr != strObjPtr && objPtr->refCount == 0) {
+
+ Jim_FreeNewObj(interp, objPtr);
+ }
+
+ return strObjPtr;
+}
+
+
+#ifdef HAVE_ISASCII
+#define jim_isascii isascii
+#else
+static int jim_isascii(int c)
+{
+ return !(c & ~0x7f);
+}
+#endif
+
+static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
+{
+ static const char * const strclassnames[] = {
+ "integer", "alpha", "alnum", "ascii", "digit",
+ "double", "lower", "upper", "space", "xdigit",
+ "control", "print", "graph", "punct", "boolean",
+ NULL
+ };
+ enum {
+ STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
+ STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
+ STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
+ };
+ int strclass;
+ int len;
+ int i;
+ const char *str;
+ int (*isclassfunc)(int c) = NULL;
+
+ if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(strObjPtr, &len);
+ if (len == 0) {
+ Jim_SetResultBool(interp, !strict);
+ return JIM_OK;
+ }
+
+ switch (strclass) {
+ case STR_IS_INTEGER:
+ {
+ jim_wide w;
+ Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
+ return JIM_OK;
+ }
+
+ case STR_IS_DOUBLE:
+ {
+ double d;
+ Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
+ return JIM_OK;
+ }
+
+ case STR_IS_BOOLEAN:
+ {
+ int b;
+ Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
+ return JIM_OK;
+ }
+
+ case STR_IS_ALPHA: isclassfunc = isalpha; break;
+ case STR_IS_ALNUM: isclassfunc = isalnum; break;
+ case STR_IS_ASCII: isclassfunc = jim_isascii; break;
+ case STR_IS_DIGIT: isclassfunc = isdigit; break;
+ case STR_IS_LOWER: isclassfunc = islower; break;
+ case STR_IS_UPPER: isclassfunc = isupper; break;
+ case STR_IS_SPACE: isclassfunc = isspace; break;
+ case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
+ case STR_IS_CONTROL: isclassfunc = iscntrl; break;
+ case STR_IS_PRINT: isclassfunc = isprint; break;
+ case STR_IS_GRAPH: isclassfunc = isgraph; break;
+ case STR_IS_PUNCT: isclassfunc = ispunct; break;
+ default:
+ return JIM_ERR;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (!isclassfunc(UCHAR(str[i]))) {
+ Jim_SetResultBool(interp, 0);
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultBool(interp, 1);
+ return JIM_OK;
+}
+
+
+
+static const Jim_ObjType comparedStringObjType = {
+ "compared-string",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
+{
+ if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
+ return 1;
+ }
+ else {
+ if (strcmp(str, Jim_String(objPtr)) != 0)
+ return 0;
+
+ if (objPtr->typePtr != &comparedStringObjType) {
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &comparedStringObjType;
+ }
+ objPtr->internalRep.ptr = (char *)str;
+ return 1;
+ }
+}
+
+static int qsortCompareStringPointers(const void *a, const void *b)
+{
+ char *const *sa = (char *const *)a;
+ char *const *sb = (char *const *)b;
+
+ return strcmp(*sa, *sb);
+}
+
+
+
+static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType sourceObjType = {
+ "source",
+ FreeSourceInternalRep,
+ DupSourceInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
+}
+
+void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
+ Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
+}
+
+static const Jim_ObjType scriptLineObjType = {
+ "scriptline",
+ NULL,
+ NULL,
+ NULL,
+ JIM_NONE,
+};
+
+static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
+{
+ Jim_Obj *objPtr;
+
+#ifdef DEBUG_SHOW_SCRIPT
+ char buf[100];
+ snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
+ objPtr = Jim_NewStringObj(interp, buf, -1);
+#else
+ objPtr = Jim_NewEmptyStringObj(interp);
+#endif
+ objPtr->typePtr = &scriptLineObjType;
+ objPtr->internalRep.scriptLineValue.argc = argc;
+ objPtr->internalRep.scriptLineValue.line = line;
+
+ return objPtr;
+}
+
+static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType scriptObjType = {
+ "script",
+ FreeScriptInternalRep,
+ DupScriptInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+typedef struct ScriptToken
+{
+ Jim_Obj *objPtr;
+ int type;
+} ScriptToken;
+
+typedef struct ScriptObj
+{
+ ScriptToken *token;
+ Jim_Obj *fileNameObj;
+ int len;
+ int substFlags;
+ int inUse; /* Used to share a ScriptObj. Currently
+ only used by Jim_EvalObj() as protection against
+ shimmering of the currently evaluated object. */
+ int firstline;
+ int linenr;
+ int missing;
+} ScriptObj;
+
+static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+static int JimParseCheckMissing(Jim_Interp *interp, int ch);
+static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
+
+void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+ struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
+
+ if (--script->inUse != 0)
+ return;
+ for (i = 0; i < script->len; i++) {
+ Jim_DecrRefCount(interp, script->token[i].objPtr);
+ }
+ Jim_Free(script->token);
+ Jim_DecrRefCount(interp, script->fileNameObj);
+ Jim_Free(script);
+}
+
+void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+ dupPtr->typePtr = NULL;
+}
+
+typedef struct
+{
+ const char *token;
+ int len;
+ int type;
+ int line;
+} ParseToken;
+
+typedef struct
+{
+
+ ParseToken *list;
+ int size;
+ int count;
+ ParseToken static_list[20];
+} ParseTokenList;
+
+static void ScriptTokenListInit(ParseTokenList *tokenlist)
+{
+ tokenlist->list = tokenlist->static_list;
+ tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
+ tokenlist->count = 0;
+}
+
+static void ScriptTokenListFree(ParseTokenList *tokenlist)
+{
+ if (tokenlist->list != tokenlist->static_list) {
+ Jim_Free(tokenlist->list);
+ }
+}
+
+static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
+ int line)
+{
+ ParseToken *t;
+
+ if (tokenlist->count == tokenlist->size) {
+
+ tokenlist->size *= 2;
+ if (tokenlist->list != tokenlist->static_list) {
+ tokenlist->list =
+ Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
+ }
+ else {
+
+ tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
+ memcpy(tokenlist->list, tokenlist->static_list,
+ tokenlist->count * sizeof(*tokenlist->list));
+ }
+ }
+ t = &tokenlist->list[tokenlist->count++];
+ t->token = token;
+ t->len = len;
+ t->type = type;
+ t->line = line;
+}
+
+static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
+{
+ int expand = 1;
+ int count = 0;
+
+
+ if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
+ if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
+
+ expand = -1;
+ t++;
+ }
+ else {
+ if (script->missing == ' ') {
+
+ script->missing = '}';
+ script->linenr = t[1].line;
+ }
+ }
+ }
+
+
+ while (!TOKEN_IS_SEP(t->type)) {
+ t++;
+ count++;
+ }
+
+ return count * expand;
+}
+
+static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
+{
+ Jim_Obj *objPtr;
+
+ if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
+
+ int len = t->len;
+ char *str = Jim_Alloc(len + 1);
+ len = JimEscape(str, t->token, len);
+ objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
+ }
+ else {
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ }
+ return objPtr;
+}
+
+static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ int lineargs = 0;
+
+ ScriptToken *linefirst;
+ int count;
+ int linenr;
+
+#ifdef DEBUG_SHOW_SCRIPT_TOKENS
+ printf("==== Tokens ====\n");
+ for (i = 0; i < tokenlist->count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
+ tokenlist->list[i].len, tokenlist->list[i].token);
+ }
+#endif
+
+
+ count = tokenlist->count;
+ for (i = 0; i < tokenlist->count; i++) {
+ if (tokenlist->list[i].type == JIM_TT_EOL) {
+ count++;
+ }
+ }
+ linenr = script->firstline = tokenlist->list[0].line;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+
+ linefirst = token++;
+
+ for (i = 0; i < tokenlist->count; ) {
+
+ int wordtokens;
+
+
+ while (tokenlist->list[i].type == JIM_TT_SEP) {
+ i++;
+ }
+
+ wordtokens = JimCountWordTokens(script, tokenlist->list + i);
+
+ if (wordtokens == 0) {
+
+ if (lineargs) {
+ linefirst->type = JIM_TT_LINE;
+ linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
+ Jim_IncrRefCount(linefirst->objPtr);
+
+
+ lineargs = 0;
+ linefirst = token++;
+ }
+ i++;
+ continue;
+ }
+ else if (wordtokens != 1) {
+
+ token->type = JIM_TT_WORD;
+ token->objPtr = Jim_NewIntObj(interp, wordtokens);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ if (wordtokens < 0) {
+
+ i++;
+ wordtokens = -wordtokens - 1;
+ lineargs--;
+ }
+ }
+
+ if (lineargs == 0) {
+
+ linenr = tokenlist->list[i].line;
+ }
+ lineargs++;
+
+
+ while (wordtokens--) {
+ const ParseToken *t = &tokenlist->list[i++];
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+
+ Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+ token++;
+ }
+ }
+
+ if (lineargs == 0) {
+ token--;
+ }
+
+ script->len = token - script->token;
+
+ JimPanic((script->len >= count, "allocated script array is too short"));
+
+#ifdef DEBUG_SHOW_SCRIPT
+ printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
+ for (i = 0; i < script->len; i++) {
+ const ScriptToken *t = &script->token[i];
+ printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+ }
+#endif
+
+}
+
+int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr)
+{
+ ScriptObj *script = JimGetScript(interp, scriptObj);
+ if (stateCharPtr) {
+ *stateCharPtr = script->missing;
+ }
+ return script->missing == ' ' || script->missing == '}';
+}
+
+static int JimParseCheckMissing(Jim_Interp *interp, int ch)
+{
+ const char *msg;
+
+ switch (ch) {
+ case '\\':
+ case ' ':
+ return JIM_OK;
+
+ case '[':
+ msg = "unmatched \"[\"";
+ break;
+ case '{':
+ msg = "missing close-brace";
+ break;
+ case '}':
+ msg = "extra characters after close-brace";
+ break;
+ case '"':
+ default:
+ msg = "missing quote";
+ break;
+ }
+
+ Jim_SetResultString(interp, msg, -1);
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
+{
+ int line;
+ Jim_Obj *fileNameObj;
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else if (objPtr->typePtr == &scriptObjType) {
+ ScriptObj *script = JimGetScript(interp, objPtr);
+ fileNameObj = script->fileNameObj;
+ line = script->firstline;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ *lineptr = line;
+ return fileNameObj;
+}
+
+void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_IncrRefCount(fileNameObj);
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+ objPtr->typePtr = &sourceObjType;
+}
+
+static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
+
+ for (i = 0; i < tokenlist->count; i++) {
+ const ParseToken *t = &tokenlist->list[i];
+
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ }
+
+ script->len = i;
+}
+
+static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script;
+ ParseTokenList tokenlist;
+ Jim_Obj *fileNameObj;
+ int line;
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, line);
+ while (!parser.eof) {
+ JimParseScript(&parser);
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+
+ ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
+
+
+ script = Jim_Alloc(sizeof(*script));
+ memset(script, 0, sizeof(*script));
+ script->inUse = 1;
+ script->fileNameObj = fileNameObj;
+ Jim_IncrRefCount(script->fileNameObj);
+ script->missing = parser.missing.ch;
+ script->linenr = parser.missing.line;
+
+ ScriptObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+}
+
+static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr == interp->emptyObj) {
+
+ objPtr = interp->nullScriptObj;
+ }
+
+ if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
+ JimSetScriptFromAny(interp, objPtr);
+ }
+
+ return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
+}
+
+void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
+{
+ interp->procEpoch++;
+
+
+ while (interp->oldCmdCache) {
+ Jim_Cmd *next = interp->oldCmdCache->prevCmd;
+ Jim_Free(interp->oldCmdCache);
+ interp->oldCmdCache = next;
+ }
+ interp->oldCmdCacheSize = 0;
+}
+
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+ cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+ if (--cmdPtr->inUse == 0) {
+ if (cmdPtr->isproc) {
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ if (cmdPtr->u.proc.staticVars) {
+ Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+ Jim_Free(cmdPtr->u.proc.staticVars);
+ }
+ }
+ else {
+
+ if (cmdPtr->u.native.delProc) {
+ cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
+ }
+ }
+ if (cmdPtr->prevCmd) {
+
+ JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
+ }
+
+ cmdPtr->prevCmd = interp->oldCmdCache;
+ interp->oldCmdCache = cmdPtr;
+ if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ }
+}
+
+static void JimIncrVarRef(Jim_VarVal *vv)
+{
+ vv->refCount++;
+}
+
+static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
+{
+ assert(vv->refCount > 0);
+ if (--vv->refCount == 0) {
+ if (vv->objPtr) {
+ Jim_DecrRefCount(interp, vv->objPtr);
+ }
+ Jim_Free(vv);
+ }
+}
+
+static void JimVariablesHTValDestructor(void *interp, void *val)
+{
+ JimDecrVarRef(interp, val);
+}
+
+static unsigned int JimObjectHTHashFunction(const void *key)
+{
+ Jim_Obj *keyObj = (Jim_Obj *)key;
+ int length;
+ const char *string;
+
+#ifdef JIM_OPTIMIZATION
+ if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
+
+ jim_wide objValue = JimWideValue(keyObj);
+ if (objValue > INT_MIN && objValue < INT_MAX) {
+ unsigned result = 0;
+ unsigned value = (unsigned)objValue;
+
+ if (objValue < 0) {
+ value = (unsigned)-objValue;
+ }
+
+
+ do {
+ result += (result << 3) + (value % 10 + '0');
+ value /= 10;
+ } while (value);
+
+ if (objValue < 0) {
+ result += (result << 3) + '-';
+ }
+ return result;
+ }
+ }
+#endif
+ string = Jim_GetString(keyObj, &length);
+ return Jim_GenHashFunction((const unsigned char *)string, length);
+}
+
+static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+}
+
+static void *JimObjectHTKeyValDup(void *privdata, const void *val)
+{
+ Jim_IncrRefCount((Jim_Obj *)val);
+ return (void *)val;
+}
+
+static void JimObjectHTKeyValDestructor(void *interp, void *val)
+{
+ Jim_DecrRefCount(interp, (Jim_Obj *)val);
+}
+
+
+static void *JimVariablesHTValDup(void *privdata, const void *val)
+{
+ JimIncrVarRef((Jim_VarVal *)val);
+ return (void *)val;
+}
+
+static const Jim_HashTableType JimVariablesHashTableType = {
+ JimObjectHTHashFunction,
+ JimObjectHTKeyValDup,
+ JimVariablesHTValDup,
+ JimObjectHTKeyCompare,
+ JimObjectHTKeyValDestructor,
+ JimVariablesHTValDestructor
+};
+
+
+static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
+{
+ int len;
+ const char *str = Jim_GetString(objPtr, &len);
+ if (len >= 2 && str[0] == ':' && str[1] == ':') {
+ while (len && *str == ':') {
+ len--;
+ str++;
+ }
+ }
+ *length = len;
+ return str;
+}
+
+static unsigned int JimCommandsHT_HashFunction(const void *key)
+{
+ int len;
+ const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
+ return Jim_GenHashFunction((const unsigned char *)str, len);
+}
+
+static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ int len1, len2;
+ const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
+ const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
+ return len1 == len2 && memcmp(str1, str2, len1) == 0;
+}
+
+static void JimCommandsHT_ValDestructor(void *interp, void *val)
+{
+ JimDecrCmdRefCount(interp, val);
+}
+
+static const Jim_HashTableType JimCommandsHashTableType = {
+ JimCommandsHT_HashFunction,
+ JimObjectHTKeyValDup,
+ NULL,
+ JimCommandsHT_KeyCompare,
+ JimObjectHTKeyValDestructor,
+ JimCommandsHT_ValDestructor
+};
+
+
+
+Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
+{
+#ifdef jim_ext_namespace
+ Jim_Obj *resultObj;
+
+ const char *name = Jim_String(nameObjPtr);
+ if (name[0] == ':' && name[1] == ':') {
+ return nameObjPtr;
+ }
+ Jim_IncrRefCount(nameObjPtr);
+ resultObj = Jim_NewStringObj(interp, "::", -1);
+ Jim_AppendObj(interp, resultObj, nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+
+ return resultObj;
+#else
+ return nameObjPtr;
+#endif
+}
+
+static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef jim_ext_namespace
+ if (Jim_Length(interp->framePtr->nsObj)) {
+ int len;
+ const char *name = Jim_GetString(objPtr, &len);
+ if (len < 2 || name[0] != ':' || name[1] != ':') {
+
+ objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+ Jim_AppendStrings(interp, objPtr, "::", name, NULL);
+ }
+ }
+#endif
+ Jim_IncrRefCount(objPtr);
+ return objPtr;
+}
+
+static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
+{
+ JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));
+
+ if (interp->local) {
+ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
+ if (he) {
+
+ cmd->prevCmd = Jim_GetHashEntryVal(he);
+ Jim_SetHashVal(&interp->commands, he, cmd);
+
+ Jim_InterpIncrProcEpoch(interp);
+ return;
+ }
+ }
+
+
+
+ Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
+}
+
+int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+{
+ Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
+
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->u.native.delProc = delProc;
+ cmdPtr->u.native.cmdProc = cmdProc;
+ cmdPtr->u.native.privData = privData;
+
+ Jim_IncrRefCount(cmdNameObj);
+ JimCreateCommand(interp, cmdNameObj, cmdPtr);
+ Jim_DecrRefCount(interp, cmdNameObj);
+
+ return JIM_OK;
+}
+
+
+int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
+ Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+{
+ return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
+}
+
+static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
+{
+ int len, i;
+
+ len = Jim_ListLength(interp, staticsListObjPtr);
+ if (len == 0) {
+ return JIM_OK;
+ }
+
+ cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
+ Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
+ for (i = 0; i < len; i++) {
+ Jim_Obj *initObjPtr = NULL;
+ Jim_Obj *nameObjPtr;
+ Jim_VarVal *vv = NULL;
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
+ int subLen = Jim_ListLength(interp, objPtr);
+ int byref = 0;
+
+
+ if (subLen != 1 && subLen != 2) {
+ Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+ objPtr);
+ return JIM_ERR;
+ }
+
+ nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
+
+
+ if (subLen == 1) {
+ int len;
+ const char *pt = Jim_GetString(nameObjPtr, &len);
+ if (*pt == '&') {
+
+ nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
+ byref = 1;
+ }
+ }
+ Jim_IncrRefCount(nameObjPtr);
+
+ if (subLen == 1) {
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+
+ if (byref) {
+ Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
+ }
+ else {
+ Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
+ }
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+
+ case JIM_OK:
+ if (byref) {
+ vv = nameObjPtr->internalRep.varValue.vv;
+ }
+ else {
+ initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+ }
+ break;
+
+ case JIM_ERR:
+
+ Jim_SetResultFormatted(interp,
+ "variable for initialization of static \"%#s\" not found in the local context",
+ nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+ initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
+ }
+
+ if (vv == NULL) {
+ vv = Jim_Alloc(sizeof(*vv));
+ vv->objPtr = initObjPtr;
+ Jim_IncrRefCount(vv->objPtr);
+ vv->linkFramePtr = NULL;
+ vv->refCount = 0;
+ }
+
+ if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
+ Jim_SetResultFormatted(interp,
+ "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+ JimIncrVarRef(vv);
+ JimDecrVarRef(interp, vv);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return JIM_ERR;
+ }
+
+ Jim_DecrRefCount(interp, nameObjPtr);
+ }
+ return JIM_OK;
+}
+
+
+#ifdef jim_ext_namespace
+static const char *Jim_memrchr(const char *p, int c, int len)
+{
+ int i;
+ for (i = len; i > 0; i--) {
+ if (p[i] == c) {
+ return p + i;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
+{
+#ifdef jim_ext_namespace
+ if (cmdPtr->isproc) {
+ int len;
+ const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);
+
+ const char *pt = Jim_memrchr(cmdname, ':', len);
+ if (pt && pt != cmdname && pt[-1] == ':') {
+ pt++;
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
+ if (Jim_FindHashEntry(&interp->commands, tempObj)) {
+
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ }
+#endif
+}
+
+static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
+ Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
+{
+ Jim_Cmd *cmdPtr;
+ int argListLen;
+ int i;
+
+ argListLen = Jim_ListLength(interp, argListObjPtr);
+
+
+ cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+ assert(cmdPtr);
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->isproc = 1;
+ cmdPtr->u.proc.argListObjPtr = argListObjPtr;
+ cmdPtr->u.proc.argListLen = argListLen;
+ cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
+ cmdPtr->u.proc.argsPos = -1;
+ cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
+ cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
+ Jim_IncrRefCount(argListObjPtr);
+ Jim_IncrRefCount(bodyObjPtr);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+
+ if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+
+
+ for (i = 0; i < argListLen; i++) {
+ Jim_Obj *argPtr;
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ int len;
+
+
+ argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
+ len = Jim_ListLength(interp, argPtr);
+ if (len == 0) {
+ Jim_SetResultString(interp, "argument with no name", -1);
+err:
+ JimDecrCmdRefCount(interp, cmdPtr);
+ return NULL;
+ }
+ if (len > 2) {
+ Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
+ goto err;
+ }
+
+ if (len == 2) {
+
+ nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
+ defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
+ }
+ else {
+
+ nameObjPtr = argPtr;
+ defaultObjPtr = NULL;
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
+ if (cmdPtr->u.proc.argsPos >= 0) {
+ Jim_SetResultString(interp, "'args' specified more than once", -1);
+ goto err;
+ }
+ cmdPtr->u.proc.argsPos = i;
+ }
+ else {
+ if (len == 2) {
+ cmdPtr->u.proc.optArity++;
+ }
+ else {
+ cmdPtr->u.proc.reqArity++;
+ }
+ }
+
+ cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
+ cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
+ }
+
+ return cmdPtr;
+}
+
+int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
+{
+ int ret = JIM_OK;
+
+ nameObj = JimQualifyName(interp, nameObj);
+
+ if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
+ Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
+ ret = JIM_ERR;
+ }
+ Jim_DecrRefCount(interp, nameObj);
+
+ return ret;
+}
+
+int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
+{
+ int ret = JIM_ERR;
+ Jim_HashEntry *he;
+ Jim_Cmd *cmdPtr;
+
+ if (Jim_Length(newNameObj) == 0) {
+ return Jim_DeleteCommand(interp, oldNameObj);
+ }
+
+
+
+ oldNameObj = JimQualifyName(interp, oldNameObj);
+ newNameObj = JimQualifyName(interp, newNameObj);
+
+
+ he = Jim_FindHashEntry(&interp->commands, oldNameObj);
+ if (he == NULL) {
+ Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
+ }
+ else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
+ Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
+ }
+ else {
+ cmdPtr = Jim_GetHashEntryVal(he);
+ if (cmdPtr->prevCmd) {
+ Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
+ }
+ else {
+
+ JimIncrCmdRefCount(cmdPtr);
+ JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
+ Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);
+
+
+ Jim_DeleteHashEntry(&interp->commands, oldNameObj);
+
+
+ Jim_InterpIncrProcEpoch(interp);
+
+ ret = JIM_OK;
+ }
+ }
+
+ Jim_DecrRefCount(interp, oldNameObj);
+ Jim_DecrRefCount(interp, newNameObj);
+
+ return ret;
+}
+
+
+static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
+}
+
+static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
+ dupPtr->typePtr = srcPtr->typePtr;
+ Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
+}
+
+static const Jim_ObjType commandObjType = {
+ "command",
+ FreeCommandInternalRep,
+ DupCommandInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ Jim_Cmd *cmd;
+
+ if (objPtr->typePtr == &commandObjType
+ && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
+#ifdef jim_ext_namespace
+ && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
+#endif
+ && objPtr->internalRep.cmdValue.cmdPtr->inUse) {
+
+ cmd = objPtr->internalRep.cmdValue.cmdPtr;
+ }
+ else {
+ Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
+ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
+#ifdef jim_ext_namespace
+ if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
+ he = Jim_FindHashEntry(&interp->commands, objPtr);
+ }
+#endif
+ if (he == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
+ }
+ Jim_DecrRefCount(interp, qualifiedNameObj);
+ return NULL;
+ }
+ cmd = Jim_GetHashEntryVal(he);
+
+ cmd->cmdNameObj = Jim_GetHashEntryKey(he);
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &commandObjType;
+ objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
+ objPtr->internalRep.cmdValue.cmdPtr = cmd;
+ objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
+ Jim_IncrRefCount(interp->framePtr->nsObj);
+ Jim_DecrRefCount(interp, qualifiedNameObj);
+ }
+ while (cmd->u.proc.upcall) {
+ cmd = cmd->prevCmd;
+ }
+ return cmd;
+}
+
+
+
+static const Jim_ObjType variableObjType = {
+ "variable",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ const char *varName;
+ Jim_CallFrame *framePtr;
+ int global;
+ int len;
+ Jim_VarVal *vv;
+
+
+ if (objPtr->typePtr == &variableObjType) {
+ framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
+ if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
+
+ return JIM_OK;
+ }
+
+ }
+ else if (objPtr->typePtr == &dictSubstObjType) {
+ return JIM_DICT_SUGAR;
+ }
+
+ varName = Jim_GetString(objPtr, &len);
+
+
+ if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
+ return JIM_DICT_SUGAR;
+ }
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*varName == ':') {
+ varName++;
+ len--;
+ }
+ global = 1;
+ framePtr = interp->topFramePtr;
+
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
+ vv = JimFindVariable(&framePtr->vars, tempObj);
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ else {
+ global = 0;
+ framePtr = interp->framePtr;
+
+ vv = JimFindVariable(&framePtr->vars, objPtr);
+ if (vv == NULL && framePtr->staticVars) {
+
+ vv = JimFindVariable(framePtr->staticVars, objPtr);
+ }
+ }
+
+ if (vv == NULL) {
+ return JIM_ERR;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &variableObjType;
+ objPtr->internalRep.varValue.callFrameId = framePtr->id;
+ objPtr->internalRep.varValue.vv = vv;
+ objPtr->internalRep.varValue.global = global;
+ return JIM_OK;
+}
+
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
+
+static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
+{
+ return Jim_AddHashEntry(ht, nameObjPtr, vv);
+}
+
+static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+{
+ Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
+ if (he) {
+ return (Jim_VarVal *)Jim_GetHashEntryVal(he);
+ }
+ return NULL;
+}
+
+static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+{
+ return Jim_DeleteHashEntry(ht, nameObjPtr);
+}
+
+static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ const char *name;
+ Jim_CallFrame *framePtr;
+ int global;
+ int len;
+
+
+ Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));
+
+ vv->objPtr = valObjPtr;
+ Jim_IncrRefCount(valObjPtr);
+ vv->linkFramePtr = NULL;
+ vv->refCount = 0;
+
+ name = Jim_GetString(nameObjPtr, &len);
+ if (name[0] == ':' && name[1] == ':') {
+ while (*name == ':') {
+ name++;
+ len--;
+ }
+ framePtr = interp->topFramePtr;
+ global = 1;
+ JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
+ }
+ else {
+ framePtr = interp->framePtr;
+ global = 0;
+ JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
+ }
+
+
+ Jim_FreeIntRep(interp, nameObjPtr);
+ nameObjPtr->typePtr = &variableObjType;
+ nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
+ nameObjPtr->internalRep.varValue.vv = vv;
+ nameObjPtr->internalRep.varValue.global = global;
+
+ return vv;
+}
+
+int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+ Jim_VarVal *vv;
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+ return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
+
+ case JIM_ERR:
+ JimCreateVariable(interp, nameObjPtr, valObjPtr);
+ break;
+
+ case JIM_OK:
+ vv = nameObjPtr->internalRep.varValue.vv;
+ if (vv->linkFramePtr == NULL) {
+ Jim_IncrRefCount(valObjPtr);
+ Jim_DecrRefCount(interp, vv->objPtr);
+ vv->objPtr = valObjPtr;
+ }
+ else {
+ Jim_CallFrame *savedCallFrame;
+
+ savedCallFrame = interp->framePtr;
+ interp->framePtr = vv->linkFramePtr;
+ err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
+ interp->framePtr = savedCallFrame;
+ if (err != JIM_OK)
+ return err;
+ }
+ }
+ return JIM_OK;
+}
+
+int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_Obj *nameObjPtr;
+ int result;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ result = Jim_SetVariable(interp, nameObjPtr, objPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return result;
+}
+
+int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_CallFrame *savedFramePtr;
+ int result;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ result = Jim_SetVariableStr(interp, name, objPtr);
+ interp->framePtr = savedFramePtr;
+ return result;
+}
+
+int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
+{
+ Jim_Obj *valObjPtr;
+ int result;
+
+ valObjPtr = Jim_NewStringObj(interp, val, -1);
+ Jim_IncrRefCount(valObjPtr);
+ result = Jim_SetVariableStr(interp, name, valObjPtr);
+ Jim_DecrRefCount(interp, valObjPtr);
+ return result;
+}
+
+int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
+ Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
+{
+ const char *varName;
+ const char *targetName;
+ Jim_CallFrame *framePtr;
+ Jim_VarVal *vv;
+ int len;
+ int varnamelen;
+
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+
+ Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
+ return JIM_ERR;
+
+ case JIM_OK:
+ vv = nameObjPtr->internalRep.varValue.vv;
+
+ if (vv->linkFramePtr == NULL) {
+ Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ vv->linkFramePtr = NULL;
+ break;
+ }
+
+
+
+ varName = Jim_GetString(nameObjPtr, &varnamelen);
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*varName == ':') {
+ varName++;
+ varnamelen--;
+ }
+
+ framePtr = interp->topFramePtr;
+ }
+ else {
+ framePtr = interp->framePtr;
+ }
+
+ targetName = Jim_GetString(targetNameObjPtr, &len);
+ if (targetName[0] == ':' && targetName[1] == ':') {
+ while (*targetName == ':') {
+ targetName++;
+ len--;
+ }
+ targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
+ targetCallFrame = interp->topFramePtr;
+ }
+ Jim_IncrRefCount(targetNameObjPtr);
+
+ if (framePtr->level < targetCallFrame->level) {
+ Jim_SetResultFormatted(interp,
+ "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
+ nameObjPtr);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ if (framePtr == targetCallFrame) {
+ Jim_Obj *objPtr = targetNameObjPtr;
+
+
+ while (1) {
+ if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
+ Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+ if (SetVariableFromAny(interp, objPtr) != JIM_OK)
+ break;
+ vv = objPtr->internalRep.varValue.vv;
+ if (vv->linkFramePtr != targetCallFrame)
+ break;
+ objPtr = vv->objPtr;
+ }
+ }
+
+
+ Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
+
+ nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ if (interp->safeexpr) {
+ return nameObjPtr;
+ }
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_OK:{
+ Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;
+
+ if (vv->linkFramePtr == NULL) {
+ return vv->objPtr;
+ }
+ else {
+ Jim_Obj *objPtr;
+
+
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = vv->linkFramePtr;
+ objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
+ interp->framePtr = savedCallFrame;
+ if (objPtr) {
+ return objPtr;
+ }
+
+ }
+ }
+ break;
+
+ case JIM_DICT_SUGAR:
+
+ return JimDictSugarGet(interp, nameObjPtr, flags);
+ }
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
+ }
+ return NULL;
+}
+
+Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_Obj *nameObjPtr, *varObjPtr;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return varObjPtr;
+}
+
+Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariableStr(interp, name, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_VarVal *vv;
+ int retval;
+ Jim_CallFrame *framePtr;
+
+ retval = SetVariableFromAny(interp, nameObjPtr);
+ if (retval == JIM_DICT_SUGAR) {
+
+ return JimDictSugarSet(interp, nameObjPtr, NULL);
+ }
+ else if (retval == JIM_OK) {
+ vv = nameObjPtr->internalRep.varValue.vv;
+
+
+ if (vv->linkFramePtr) {
+ framePtr = interp->framePtr;
+ interp->framePtr = vv->linkFramePtr;
+ retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
+ interp->framePtr = framePtr;
+ }
+ else {
+ if (nameObjPtr->internalRep.varValue.global) {
+ int len;
+ const char *name = Jim_GetString(nameObjPtr, &len);
+ while (*name == ':') {
+ name++;
+ len--;
+ }
+ framePtr = interp->topFramePtr;
+ Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
+ retval = JimUnsetVariable(&framePtr->vars, tempObj);
+ Jim_FreeNewObj(interp, tempObj);
+ }
+ else {
+ framePtr = interp->framePtr;
+ retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
+ }
+
+ if (retval == JIM_OK) {
+
+ framePtr->id = interp->callFrameEpoch++;
+ }
+ }
+ }
+ if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
+ }
+ return retval;
+}
+
+
+
+static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
+{
+ const char *str, *p;
+ int len, keyLen;
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ str = Jim_GetString(objPtr, &len);
+
+ p = strchr(str, '(');
+ JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+
+ varObjPtr = Jim_NewStringObj(interp, str, p - str);
+
+ p++;
+ keyLen = (str + len) - p;
+ if (str[len - 1] == ')') {
+ keyLen--;
+ }
+
+
+ keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ *varPtrPtr = varObjPtr;
+ *keyPtrPtr = keyObjPtr;
+}
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
+
+ if (err == JIM_OK) {
+
+ Jim_SetEmptyResult(interp);
+ }
+ else {
+ if (!valObjPtr) {
+
+ if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
+ objPtr);
+ return err;
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
+ (valObjPtr ? "set" : "unset"), objPtr);
+ }
+ return err;
+}
+
+static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
+ Jim_Obj *keyObjPtr, int flags)
+{
+ Jim_Obj *dictObjPtr;
+ Jim_Obj *resObjPtr = NULL;
+ int ret;
+
+ dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
+ if (!dictObjPtr) {
+ return NULL;
+ }
+
+ ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+ if (ret != JIM_OK) {
+ Jim_SetResultFormatted(interp,
+ "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
+ ret < 0 ? "variable isn't" : "no such element in");
+ }
+ else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
+
+ Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
+ }
+
+ return resObjPtr;
+}
+
+
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ SetDictSubstFromAny(interp, objPtr);
+
+ return JimDictExpandArrayVariable(interp,
+ objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
+}
+
+
+
+void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+
+ dupPtr->internalRep = srcPtr->internalRep;
+
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &dictSubstObjType) {
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ if (objPtr->typePtr == &interpolatedObjType) {
+
+
+ varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
+ keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ }
+ else {
+ JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &dictSubstObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
+ }
+}
+
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *resObjPtr = NULL;
+ Jim_Obj *substKeyObjPtr = NULL;
+
+ if (interp->safeexpr) {
+ return objPtr;
+ }
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
+ &substKeyObjPtr, JIM_NONE)
+ != JIM_OK) {
+ return NULL;
+ }
+ Jim_IncrRefCount(substKeyObjPtr);
+ resObjPtr =
+ JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ substKeyObjPtr, 0);
+ Jim_DecrRefCount(interp, substKeyObjPtr);
+
+ return resObjPtr;
+}
+
+
+static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *cf;
+
+ if (interp->freeFramesList) {
+ cf = interp->freeFramesList;
+ interp->freeFramesList = cf->next;
+
+ cf->argv = NULL;
+ cf->argc = 0;
+ cf->procArgsObjPtr = NULL;
+ cf->procBodyObjPtr = NULL;
+ cf->next = NULL;
+ cf->staticVars = NULL;
+ cf->localCommands = NULL;
+ cf->tailcallObj = NULL;
+ cf->tailcallCmd = NULL;
+ }
+ else {
+ cf = Jim_Alloc(sizeof(*cf));
+ memset(cf, 0, sizeof(*cf));
+
+ Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
+ }
+
+ cf->id = interp->callFrameEpoch++;
+ cf->parent = parent;
+ cf->level = parent ? parent->level + 1 : 0;
+ cf->nsObj = nsObj;
+ Jim_IncrRefCount(nsObj);
+
+ return cf;
+}
+
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
+{
+
+ if (localCommands) {
+ Jim_Obj *cmdNameObj;
+
+ while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
+ Jim_HashTable *ht = &interp->commands;
+ Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
+ if (he) {
+ Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
+ if (cmd->prevCmd) {
+ Jim_Cmd *prevCmd = cmd->prevCmd;
+ cmd->prevCmd = NULL;
+
+
+ JimDecrCmdRefCount(interp, cmd);
+
+
+ Jim_SetHashVal(ht, he, prevCmd);
+ }
+ else {
+ Jim_DeleteHashEntry(ht, cmdNameObj);
+ }
+ }
+ Jim_DecrRefCount(interp, cmdNameObj);
+ }
+ Jim_FreeStack(localCommands);
+ Jim_Free(localCommands);
+ }
+ return JIM_OK;
+}
+
+static int JimInvokeDefer(Jim_Interp *interp, int retcode)
+{
+ Jim_Obj *objPtr;
+
+
+ if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
+ return retcode;
+ }
+ objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);
+
+ if (objPtr) {
+ int ret = JIM_OK;
+ int i;
+ int listLen = Jim_ListLength(interp, objPtr);
+ Jim_Obj *resultObjPtr;
+
+ Jim_IncrRefCount(objPtr);
+
+ resultObjPtr = Jim_GetResult(interp);
+ Jim_IncrRefCount(resultObjPtr);
+ Jim_SetEmptyResult(interp);
+
+
+ for (i = listLen; i > 0; i--) {
+
+ Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
+ ret = Jim_EvalObj(interp, scriptObjPtr);
+ if (ret != JIM_OK) {
+ break;
+ }
+ }
+
+ if (ret == JIM_OK || retcode == JIM_ERR) {
+
+ Jim_SetResult(interp, resultObjPtr);
+ }
+ else {
+ retcode = ret;
+ }
+
+ Jim_DecrRefCount(interp, resultObjPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ return retcode;
+}
+
+#define JIM_FCF_FULL 0
+#define JIM_FCF_REUSE 1
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
+ {
+ JimDeleteLocalProcs(interp, cf->localCommands);
+
+ if (cf->procArgsObjPtr)
+ Jim_DecrRefCount(interp, cf->procArgsObjPtr);
+ if (cf->procBodyObjPtr)
+ Jim_DecrRefCount(interp, cf->procBodyObjPtr);
+ Jim_DecrRefCount(interp, cf->nsObj);
+ if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
+ Jim_FreeHashTable(&cf->vars);
+ else {
+ Jim_ClearHashTable(&cf->vars);
+ }
+ cf->next = interp->freeFramesList;
+ interp->freeFramesList = cf;
+}
+
+
+
+int Jim_IsBigEndian(void)
+{
+ union {
+ unsigned short s;
+ unsigned char c[2];
+ } uval = {0x0102};
+
+ return uval.c[0] == 1;
+}
+
+
+Jim_Interp *Jim_CreateInterp(void)
+{
+ Jim_Interp *i = Jim_Alloc(sizeof(*i));
+
+ memset(i, 0, sizeof(*i));
+
+ i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
+ i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
+ i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+
+ Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
+#ifdef JIM_REFERENCES
+ Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
+#endif
+ Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
+ Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
+ i->emptyObj = Jim_NewEmptyStringObj(i);
+ i->trueObj = Jim_NewIntObj(i, 1);
+ i->falseObj = Jim_NewIntObj(i, 0);
+ i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
+ i->result = i->emptyObj;
+ i->stackTrace = Jim_NewListObj(i, NULL, 0);
+ i->unknown = Jim_NewStringObj(i, "unknown", -1);
+ i->defer = Jim_NewStringObj(i, "jim::defer", -1);
+ i->errorProc = i->emptyObj;
+ i->nullScriptObj = Jim_NewEmptyStringObj(i);
+ i->evalFrame = &i->topEvalFrame;
+ i->currentFilenameObj = Jim_NewEmptyStringObj(i);
+ Jim_IncrRefCount(i->emptyObj);
+ Jim_IncrRefCount(i->result);
+ Jim_IncrRefCount(i->stackTrace);
+ Jim_IncrRefCount(i->unknown);
+ Jim_IncrRefCount(i->defer);
+ Jim_IncrRefCount(i->nullScriptObj);
+ Jim_IncrRefCount(i->errorProc);
+ Jim_IncrRefCount(i->trueObj);
+ Jim_IncrRefCount(i->falseObj);
+ Jim_IncrRefCount(i->currentFilenameObj);
+
+
+ Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
+ Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
+
+ Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
+ Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
+ Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+ Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
+
+ return i;
+}
+
+void Jim_FreeInterp(Jim_Interp *i)
+{
+ Jim_CallFrame *cf, *cfx;
+
+ Jim_Obj *objPtr, *nextObjPtr;
+
+ i->quitting = 1;
+
+
+ for (cf = i->framePtr; cf; cf = cfx) {
+
+ JimInvokeDefer(i, JIM_OK);
+ cfx = cf->parent;
+ JimFreeCallFrame(i, cf, JIM_FCF_FULL);
+ }
+
+
+ Jim_FreeHashTable(&i->commands);
+
+ Jim_DecrRefCount(i, i->emptyObj);
+ Jim_DecrRefCount(i, i->trueObj);
+ Jim_DecrRefCount(i, i->falseObj);
+ Jim_DecrRefCount(i, i->result);
+ Jim_DecrRefCount(i, i->stackTrace);
+ Jim_DecrRefCount(i, i->errorProc);
+ Jim_DecrRefCount(i, i->unknown);
+ Jim_DecrRefCount(i, i->defer);
+ Jim_DecrRefCount(i, i->nullScriptObj);
+ Jim_DecrRefCount(i, i->currentFilenameObj);
+
+
+ Jim_InterpIncrProcEpoch(i);
+
+#ifdef JIM_REFERENCES
+ Jim_FreeHashTable(&i->references);
+#endif
+ Jim_FreeHashTable(&i->packages);
+ Jim_Free(i->prngState);
+ Jim_FreeHashTable(&i->assocData);
+ if (i->traceCmdObj) {
+ Jim_DecrRefCount(i, i->traceCmdObj);
+ }
+
+#ifdef JIM_MAINTAINER
+ if (i->liveList != NULL) {
+ objPtr = i->liveList;
+
+ printf("\n-------------------------------------\n");
+ printf("Objects still in the free list:\n");
+ while (objPtr) {
+ const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
+ Jim_String(objPtr);
+
+ if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
+ printf("%p (%d) %-10s: '%.20s...'\n",
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
+ }
+ else {
+ printf("%p (%d) %-10s: '%s'\n",
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
+ }
+ if (objPtr->typePtr == &sourceObjType) {
+ printf("FILE %s LINE %d\n",
+ Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
+ objPtr->internalRep.sourceValue.lineNumber);
+ }
+ objPtr = objPtr->nextObjPtr;
+ }
+ printf("-------------------------------------\n\n");
+ JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
+ }
+#endif
+
+
+ objPtr = i->freeList;
+ while (objPtr) {
+ nextObjPtr = objPtr->nextObjPtr;
+ Jim_Free(objPtr);
+ objPtr = nextObjPtr;
+ }
+
+
+ for (cf = i->freeFramesList; cf; cf = cfx) {
+ cfx = cf->next;
+ if (cf->vars.table)
+ Jim_FreeHashTable(&cf->vars);
+ Jim_Free(cf);
+ }
+
+
+ Jim_Free(i);
+}
+
+Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+ long level;
+ const char *str;
+ Jim_CallFrame *framePtr;
+
+ if (levelObjPtr) {
+ str = Jim_String(levelObjPtr);
+ if (str[0] == '#') {
+ char *endptr;
+
+ level = jim_strtol(str + 1, &endptr);
+ if (str[1] == '\0' || endptr[0] != '\0') {
+ level = -1;
+ }
+ }
+ else {
+ if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
+ level = -1;
+ }
+ else {
+
+ level = interp->framePtr->level - level;
+ }
+ }
+ }
+ else {
+ str = "1";
+ level = interp->framePtr->level - 1;
+ }
+
+ if (level == 0) {
+ return interp->topFramePtr;
+ }
+ if (level > 0) {
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
+ return NULL;
+}
+
+static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
+{
+ Jim_CallFrame *framePtr;
+
+ if (level == 0) {
+ return interp->framePtr;
+ }
+
+ if (level < 0) {
+
+ level = interp->framePtr->level + level;
+ }
+
+ if (level > 0) {
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+ return NULL;
+}
+
+static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
+{
+ Jim_EvalFrame *evalFrame;
+
+ if (proclevel == 0) {
+ return interp->evalFrame;
+ }
+
+ if (proclevel < 0) {
+
+ proclevel = interp->procLevel + proclevel;
+ }
+
+ if (proclevel >= 0) {
+
+ for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
+ if (evalFrame->procLevel == proclevel) {
+ return evalFrame;
+ }
+ }
+ }
+ return NULL;
+}
+
+static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
+{
+ if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
+ Jim_EvalFrame *e;
+ for (e = frame->parent; e; e = e->parent) {
+ if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
+ break;
+ }
+ }
+ if (e && e->cmd && e->cmd->cmdNameObj) {
+ return e->cmd->cmdNameObj;
+ }
+ }
+ return NULL;
+}
+
+static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
+{
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ Jim_Obj *fileNameObj = interp->emptyObj;
+ int linenr = 1;
+
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+ fileNameObj = script->fileNameObj;
+ linenr = script->linenr;
+ }
+
+ Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
+ Jim_ListAppendElement(interp, listObj, fileNameObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
+}
+
+static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+{
+
+ Jim_IncrRefCount(stackTraceObj);
+ Jim_DecrRefCount(interp, interp->stackTrace);
+ interp->stackTrace = stackTraceObj;
+ interp->errorFlag = 1;
+}
+
+static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
+{
+ if (!interp->errorFlag) {
+ int i;
+ Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
+
+ if (interp->procLevel == 0 && script) {
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
+ Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
+ Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
+ }
+ else {
+ for (i = 0; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame) {
+ JimAddStackFrame(interp, frame, stackTrace);
+ }
+ }
+ }
+ JimSetStackTrace(interp, stackTrace);
+ }
+}
+
+int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
+ void *data)
+{
+ AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
+
+ assocEntryPtr->delProc = delProc;
+ assocEntryPtr->data = data;
+ return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
+}
+
+void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
+{
+ Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
+
+ if (entryPtr != NULL) {
+ AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
+ return assocEntryPtr->data;
+ }
+ return NULL;
+}
+
+int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
+{
+ return Jim_DeleteHashEntry(&interp->assocData, key);
+}
+
+int Jim_GetExitCode(Jim_Interp *interp)
+{
+ return interp->exitCode;
+}
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr);
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+static const Jim_ObjType intObjType = {
+ "int",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+static const Jim_ObjType coercedDoubleObjType = {
+ "coerced-double",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr)
+{
+ char buf[JIM_INTEGER_SPACE + 1];
+ jim_wide wideValue = JimWideValue(objPtr);
+ int pos = 0;
+
+ if (wideValue == 0) {
+ buf[pos++] = '0';
+ }
+ else {
+ char tmp[JIM_INTEGER_SPACE];
+ int num = 0;
+ int i;
+
+ if (wideValue < 0) {
+ buf[pos++] = '-';
+ i = wideValue % 10;
+ tmp[num++] = (i > 0) ? (10 - i) : -i;
+ wideValue /= -10;
+ }
+
+ while (wideValue) {
+ tmp[num++] = wideValue % 10;
+ wideValue /= 10;
+ }
+
+ for (i = 0; i < num; i++) {
+ buf[pos++] = '0' + tmp[num - i - 1];
+ }
+ }
+ buf[pos] = 0;
+
+ JimSetStringBytes(objPtr, buf);
+}
+
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ jim_wide wideValue;
+ const char *str;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+
+ objPtr->typePtr = &intObjType;
+ return JIM_OK;
+ }
+
+
+ str = Jim_String(objPtr);
+
+ if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
+ }
+ return JIM_ERR;
+ }
+ if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
+ Jim_SetResultString(interp, "Integer value too big to be represented", -1);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &intObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+}
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &intObjType;
+}
+#endif
+
+int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ int ret = JIM_OK;
+
+ if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
+ SetIntFromAny(interp, objPtr, 0);
+ }
+ if (objPtr->typePtr == &intObjType) {
+ *widePtr = JimWideValue(objPtr);
+ }
+ else {
+ JimPanic((interp->safeexpr, "interp->safeexpr is set"));
+ interp->safeexpr++;
+ ret = Jim_EvalExpression(interp, objPtr);
+ interp->safeexpr--;
+
+ if (ret == JIM_OK) {
+ ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
+ }
+ if (ret != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
+ }
+ }
+ return ret;
+}
+
+
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
+{
+ jim_wide wideValue;
+ int retval;
+
+ retval = Jim_GetWide(interp, objPtr, &wideValue);
+ if (retval == JIM_OK) {
+ *longPtr = (long)wideValue;
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &intObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.wideValue = wideValue;
+ return objPtr;
+}
+
+#define JIM_DOUBLE_SPACE 30
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType doubleObjType = {
+ "double",
+ NULL,
+ NULL,
+ UpdateStringOfDouble,
+ JIM_TYPE_NONE,
+};
+
+#if !HAVE_DECL_ISNAN
+#undef isnan
+#define isnan(X) ((X) != (X))
+#endif
+#if !HAVE_DECL_ISINF
+#undef isinf
+#define isinf(X) (1.0 / (X) == 0.0)
+#endif
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
+{
+ double value = objPtr->internalRep.doubleValue;
+
+ if (isnan(value)) {
+ JimSetStringBytes(objPtr, "NaN");
+ return;
+ }
+ if (isinf(value)) {
+ if (value < 0) {
+ JimSetStringBytes(objPtr, "-Inf");
+ }
+ else {
+ JimSetStringBytes(objPtr, "Inf");
+ }
+ return;
+ }
+ {
+ char buf[JIM_DOUBLE_SPACE + 1];
+ int i;
+ int len = sprintf(buf, "%.12g", value);
+
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '.' || buf[i] == 'e') {
+#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
+ char *e = strchr(buf, 'e');
+ if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
+
+ e += 2;
+ memmove(e, e + 1, len - (e - buf));
+ }
+#endif
+ break;
+ }
+ }
+ if (buf[i] == '\0') {
+ buf[i++] = '.';
+ buf[i++] = '0';
+ buf[i] = '\0';
+ }
+ JimSetStringBytes(objPtr, buf);
+ }
+}
+
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ double doubleValue;
+ jim_wide wideValue;
+ const char *str;
+
+#ifdef HAVE_LONG_LONG
+
+#define MIN_INT_IN_DOUBLE -(1LL << 53)
+#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
+
+ if (objPtr->typePtr == &intObjType
+ && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
+ && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
+
+
+ objPtr->typePtr = &coercedDoubleObjType;
+ return JIM_OK;
+ }
+#endif
+ str = Jim_String(objPtr);
+
+ if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &coercedDoubleObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+ }
+ else {
+
+ if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ }
+ objPtr->typePtr = &doubleObjType;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return JIM_OK;
+}
+
+int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
+{
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ return JIM_OK;
+ }
+ if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ }
+ else {
+ *doublePtr = objPtr->internalRep.doubleValue;
+ }
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &doubleObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return objPtr;
+}
+
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
+{
+ if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+ return JIM_ERR;
+ *booleanPtr = (int) JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+static const char * const jim_true_false_strings[8] = {
+ "1", "true", "yes", "on",
+ "0", "false", "no", "off"
+};
+
+static const int jim_true_false_lens[8] = {
+ 1, 4, 3, 2,
+ 1, 5, 2, 3,
+};
+
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
+ sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
+ if (index < 0) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
+ }
+ return JIM_ERR;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &intObjType;
+
+ objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
+ return JIM_OK;
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
+static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfList(struct Jim_Obj *objPtr);
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType listObjType = {
+ "list",
+ FreeListInternalRep,
+ DupListInternalRep,
+ UpdateStringOfList,
+ JIM_TYPE_NONE,
+};
+
+void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+
+ for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+ Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
+ }
+ Jim_Free(objPtr->internalRep.listValue.ele);
+}
+
+void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ int i;
+
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
+ dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
+ dupPtr->internalRep.listValue.ele =
+ Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
+ memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
+ for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
+ Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
+ }
+ dupPtr->typePtr = &listObjType;
+}
+
+#define JIM_ELESTR_SIMPLE 0
+#define JIM_ELESTR_BRACE 1
+#define JIM_ELESTR_QUOTE 2
+static unsigned char ListElementQuotingType(const char *s, int len)
+{
+ int i, level, blevel, trySimple = 1;
+
+
+ if (len == 0)
+ return JIM_ELESTR_BRACE;
+ if (s[0] == '"' || s[0] == '{') {
+ trySimple = 0;
+ goto testbrace;
+ }
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ trySimple = 0;
+
+ case '{':
+ case '}':
+ goto testbrace;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+
+ testbrace:
+
+ if (s[len - 1] == '\\')
+ return JIM_ELESTR_QUOTE;
+ level = 0;
+ blevel = 0;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+ if (level < 0)
+ return JIM_ELESTR_QUOTE;
+ break;
+ case '[':
+ blevel++;
+ break;
+ case ']':
+ blevel--;
+ break;
+ case '\\':
+ if (s[i + 1] == '\n')
+ return JIM_ELESTR_QUOTE;
+ else if (s[i + 1] != '\0')
+ i++;
+ break;
+ }
+ }
+ if (blevel < 0) {
+ return JIM_ELESTR_QUOTE;
+ }
+
+ if (level == 0) {
+ if (!trySimple)
+ return JIM_ELESTR_BRACE;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ return JIM_ELESTR_BRACE;
+ break;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+ }
+ return JIM_ELESTR_QUOTE;
+}
+
+static int BackslashQuoteString(const char *s, int len, char *q)
+{
+ char *p = q;
+
+ while (len--) {
+ switch (*s) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case ';':
+ case '\\':
+ *p++ = '\\';
+ *p++ = *s++;
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ s++;
+ break;
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ s++;
+ break;
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ s++;
+ break;
+ case '\f':
+ *p++ = '\\';
+ *p++ = 'f';
+ s++;
+ break;
+ case '\v':
+ *p++ = '\\';
+ *p++ = 'v';
+ s++;
+ break;
+ default:
+ *p++ = *s++;
+ break;
+ }
+ }
+ *p = '\0';
+
+ return p - q;
+}
+
+static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
+{
+ #define STATIC_QUOTING_LEN 32
+ int i, bufLen, realLength;
+ const char *strRep;
+ char *p;
+ unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
+
+
+ if (objc > STATIC_QUOTING_LEN) {
+ quotingType = Jim_Alloc(objc);
+ }
+ else {
+ quotingType = staticQuoting;
+ }
+ bufLen = 0;
+ for (i = 0; i < objc; i++) {
+ int len;
+
+ strRep = Jim_GetString(objv[i], &len);
+ quotingType[i] = ListElementQuotingType(strRep, len);
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ if (i != 0 || strRep[0] != '#') {
+ bufLen += len;
+ break;
+ }
+
+ quotingType[i] = JIM_ELESTR_BRACE;
+
+ case JIM_ELESTR_BRACE:
+ bufLen += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ bufLen += len * 2;
+ break;
+ }
+ bufLen++;
+ }
+ bufLen++;
+
+
+ p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+ realLength = 0;
+ for (i = 0; i < objc; i++) {
+ int len, qlen;
+
+ strRep = Jim_GetString(objv[i], &len);
+
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ memcpy(p, strRep, len);
+ p += len;
+ realLength += len;
+ break;
+ case JIM_ELESTR_BRACE:
+ *p++ = '{';
+ memcpy(p, strRep, len);
+ p += len;
+ *p++ = '}';
+ realLength += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ if (i == 0 && strRep[0] == '#') {
+ *p++ = '\\';
+ realLength++;
+ }
+ qlen = BackslashQuoteString(strRep, len, p);
+ p += qlen;
+ realLength += qlen;
+ break;
+ }
+
+ if (i + 1 != objc) {
+ *p++ = ' ';
+ realLength++;
+ }
+ }
+ *p = '\0';
+ objPtr->length = realLength;
+
+ if (quotingType != staticQuoting) {
+ Jim_Free(quotingType);
+ }
+}
+
+static void UpdateStringOfList(struct Jim_Obj *objPtr)
+{
+ JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
+}
+
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ struct JimParserCtx parser;
+ const char *str;
+ int strLen;
+ Jim_Obj *fileNameObj;
+ int linenr;
+
+ if (objPtr->typePtr == &listObjType) {
+ return JIM_OK;
+ }
+
+
+ if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
+ Jim_Dict *dict = objPtr->internalRep.dictValue;
+
+
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = dict->len;
+ objPtr->internalRep.listValue.maxLen = dict->maxLen;
+ objPtr->internalRep.listValue.ele = dict->table;
+
+
+ Jim_Free(dict->ht);
+
+
+ Jim_Free(dict);
+ return JIM_OK;
+ }
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
+ Jim_IncrRefCount(fileNameObj);
+
+
+ str = Jim_GetString(objPtr, &strLen);
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+ objPtr->internalRep.listValue.ele = NULL;
+
+
+ if (strLen) {
+ JimParserInit(&parser, str, strLen, linenr);
+ while (!parser.eof) {
+ Jim_Obj *elementPtr;
+
+ JimParseList(&parser);
+ if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
+ continue;
+ elementPtr = JimParserGetTokenObj(interp, &parser);
+ Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+ ListAppendElement(objPtr, elementPtr);
+ }
+ }
+ Jim_DecrRefCount(interp, fileNameObj);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &listObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.listValue.ele = NULL;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+
+ if (len) {
+ ListInsertElements(objPtr, 0, len, elements);
+ }
+
+ return objPtr;
+}
+
+static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
+ Jim_Obj ***listVec)
+{
+ *listLen = Jim_ListLength(interp, listObj);
+ *listVec = listObj->internalRep.listValue.ele;
+}
+
+
+static int JimSign(jim_wide w)
+{
+ if (w == 0) {
+ return 0;
+ }
+ else if (w < 0) {
+ return -1;
+ }
+ return 1;
+}
+
+
+struct lsort_info {
+ jmp_buf jmpbuf;
+ Jim_Obj *command;
+ Jim_Interp *interp;
+ enum {
+ JIM_LSORT_ASCII,
+ JIM_LSORT_NOCASE,
+ JIM_LSORT_INTEGER,
+ JIM_LSORT_REAL,
+ JIM_LSORT_COMMAND,
+ JIM_LSORT_DICT
+ } type;
+ int order;
+ Jim_Obj **indexv;
+ int indexc;
+ int unique;
+ int (*subfn)(Jim_Obj **, Jim_Obj **);
+};
+
+static struct lsort_info *sort_info;
+
+static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *lObj, *rObj;
+
+ if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
+ Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+ return sort_info->subfn(&lObj, &rObj);
+}
+
+
+static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+}
+
+static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
+}
+
+static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+
+ const char *left = Jim_String(*lhsObj);
+ const char *right = Jim_String(*rhsObj);
+
+ while (1) {
+ if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
+
+ jim_wide lint, rint;
+ char *lend, *rend;
+ lint = jim_strtoull(left, &lend);
+ rint = jim_strtoull(right, &rend);
+ if (lint != rint) {
+ return JimSign(lint - rint) * sort_info->order;
+ }
+ if (lend -left != rend - right) {
+ return JimSign((lend - left) - (rend - right)) * sort_info->order;
+ }
+ left = lend;
+ right = rend;
+ }
+ else {
+ int cl, cr;
+ left += utf8_tounicode_case(left, &cl, 1);
+ right += utf8_tounicode_case(right, &cr, 1);
+ if (cl != cr) {
+ return JimSign(cl - cr) * sort_info->order;
+ }
+ if (cl == 0) {
+
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+ }
+ }
+ }
+}
+
+static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ jim_wide lhs = 0, rhs = 0;
+
+ if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+ Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+
+ return JimSign(lhs - rhs) * sort_info->order;
+}
+
+static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ double lhs = 0, rhs = 0;
+
+ if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+ Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+ if (lhs == rhs) {
+ return 0;
+ }
+ if (lhs > rhs) {
+ return sort_info->order;
+ }
+ return -sort_info->order;
+}
+
+static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *compare_script;
+ int rc;
+
+ jim_wide ret = 0;
+
+
+ compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
+
+ rc = Jim_EvalObj(sort_info->interp, compare_script);
+
+ if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, rc);
+ }
+
+ return JimSign(ret) * sort_info->order;
+}
+
+static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
+{
+ int src;
+ int dst = 0;
+ Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
+
+ for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
+ if (comp(&ele[dst], &ele[src]) == 0) {
+
+ Jim_DecrRefCount(sort_info->interp, ele[dst]);
+ }
+ else {
+
+ dst++;
+ }
+ ele[dst] = ele[src];
+ }
+
+
+ dst++;
+ if (dst < listObjPtr->internalRep.listValue.len) {
+ ele[dst] = ele[src];
+ }
+
+
+ listObjPtr->internalRep.listValue.len = dst;
+}
+
+
+static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
+{
+ struct lsort_info *prev_info;
+
+ typedef int (qsort_comparator) (const void *, const void *);
+ int (*fn) (Jim_Obj **, Jim_Obj **);
+ Jim_Obj **vector;
+ int len;
+ int rc;
+
+ JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
+ SetListFromAny(interp, listObjPtr);
+
+
+ prev_info = sort_info;
+ sort_info = info;
+
+ vector = listObjPtr->internalRep.listValue.ele;
+ len = listObjPtr->internalRep.listValue.len;
+ switch (info->type) {
+ case JIM_LSORT_ASCII:
+ fn = ListSortString;
+ break;
+ case JIM_LSORT_NOCASE:
+ fn = ListSortStringNoCase;
+ break;
+ case JIM_LSORT_INTEGER:
+ fn = ListSortInteger;
+ break;
+ case JIM_LSORT_REAL:
+ fn = ListSortReal;
+ break;
+ case JIM_LSORT_COMMAND:
+ fn = ListSortCommand;
+ break;
+ case JIM_LSORT_DICT:
+ fn = ListSortDict;
+ break;
+ default:
+ fn = NULL;
+ JimPanic((1, "ListSort called with invalid sort type"));
+ return -1;
+ }
+
+ if (info->indexc) {
+
+ info->subfn = fn;
+ fn = ListSortIndexHelper;
+ }
+
+ if ((rc = setjmp(info->jmpbuf)) == 0) {
+ qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
+
+ if (info->unique && len > 1) {
+ ListRemoveDuplicates(listObjPtr, fn);
+ }
+
+ Jim_InvalidateStringRep(listObjPtr);
+ }
+ sort_info = prev_info;
+
+ return rc;
+}
+
+
+static void ListEnsureLength(Jim_Obj *listPtr, int idx)
+{
+ assert(idx >= 0);
+ if (idx >= listPtr->internalRep.listValue.maxLen) {
+ if (idx < 4) {
+
+ idx = 4;
+ }
+ listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * idx);
+
+ listPtr->internalRep.listValue.maxLen = idx;
+ }
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
+{
+ int currentLen = listPtr->internalRep.listValue.len;
+ int requiredLen = currentLen + elemc;
+ int i;
+ Jim_Obj **point;
+
+ if (elemc == 0) {
+
+ return;
+ }
+
+ if (requiredLen > listPtr->internalRep.listValue.maxLen) {
+ if (currentLen) {
+
+ requiredLen *= 2;
+ }
+ ListEnsureLength(listPtr, requiredLen);
+ }
+ if (idx < 0) {
+ idx = currentLen;
+ }
+ point = listPtr->internalRep.listValue.ele + idx;
+ memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
+ for (i = 0; i < elemc; ++i) {
+ point[i] = elemVec[i];
+ Jim_IncrRefCount(point[i]);
+ }
+ listPtr->internalRep.listValue.len += elemc;
+}
+
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ ListInsertElements(listPtr, -1, 1, &objPtr);
+}
+
+static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ ListInsertElements(listPtr, -1,
+ appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
+}
+
+void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendElement(listPtr, objPtr);
+}
+
+void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
+ SetListFromAny(interp, listPtr);
+ SetListFromAny(interp, appendListPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendList(listPtr, appendListPtr);
+}
+
+int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ SetListFromAny(interp, objPtr);
+ return objPtr->internalRep.listValue.len;
+}
+
+void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ int objc, Jim_Obj *const *objVec)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
+ idx = listPtr->internalRep.listValue.len;
+ else if (idx < 0)
+ idx = 0;
+ Jim_InvalidateStringRep(listPtr);
+ ListInsertElements(listPtr, idx, objc, objVec);
+}
+
+Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ return NULL;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ return listPtr->internalRep.listValue.ele[idx];
+}
+
+int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
+{
+ *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
+ if (*objPtrPtr == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
+ Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
+{
+ int i;
+ int static_idxes[5];
+ int *idxes = static_idxes;
+ int ret = JIM_OK;
+
+ if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
+ idxes = Jim_Alloc(indexc * sizeof(*idxes));
+ }
+
+ for (i = 0; i < indexc; i++) {
+ ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
+ if (ret != JIM_OK) {
+ goto err;
+ }
+ }
+
+ for (i = 0; i < indexc; i++) {
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
+ if (!objPtr) {
+ if (flags & JIM_ERRMSG) {
+ if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
+ Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
+ }
+ else {
+ Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
+ }
+ }
+ return -1;
+ }
+ listPtr = objPtr;
+ }
+ *resultObj = listPtr;
+err:
+ if (idxes != static_idxes)
+ Jim_Free(idxes);
+ return ret;
+}
+
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ Jim_Obj *newObjPtr, int flags)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
+ listPtr->internalRep.listValue.ele[idx] = newObjPtr;
+ Jim_IncrRefCount(newObjPtr);
+ return JIM_OK;
+}
+
+int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
+{
+ Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
+ int shared, i, idx;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < indexc - 1; i++) {
+ listObjPtr = objPtr;
+ if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
+ goto err;
+
+ objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
+ if (objPtr == NULL) {
+ Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
+ goto err;
+ }
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
+ }
+ Jim_InvalidateStringRep(listObjPtr);
+ }
+ if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
+ goto err;
+ if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
+ goto err;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+ goto err;
+ Jim_SetResult(interp, varObjPtr);
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
+{
+ int i;
+ int listLen = Jim_ListLength(interp, listObjPtr);
+ Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
+
+ for (i = 0; i < listLen; ) {
+ Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
+ if (++i != listLen) {
+ Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
+ }
+ }
+ return resObjPtr;
+}
+
+Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i;
+
+ for (i = 0; i < objc; i++) {
+ if (!Jim_IsList(objv[i]))
+ break;
+ }
+ if (i == objc) {
+ Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < objc; i++)
+ ListAppendList(objPtr, objv[i]);
+ return objPtr;
+ }
+ else {
+
+ int len = 0, objLen;
+ char *bytes, *p;
+
+
+ for (i = 0; i < objc; i++) {
+ len += Jim_Length(objv[i]);
+ }
+ if (objc)
+ len += objc - 1;
+
+ p = bytes = Jim_Alloc(len + 1);
+ for (i = 0; i < objc; i++) {
+ const char *s = Jim_GetString(objv[i], &objLen);
+
+
+ while (objLen && isspace(UCHAR(*s))) {
+ s++;
+ objLen--;
+ len--;
+ }
+
+ while (objLen && isspace(UCHAR(s[objLen - 1]))) {
+
+ if (objLen > 1 && s[objLen - 2] == '\\') {
+ break;
+ }
+ objLen--;
+ len--;
+ }
+ memcpy(p, s, objLen);
+ p += objLen;
+ if (i + 1 != objc) {
+ if (objLen)
+ *p++ = ' ';
+ else {
+ len--;
+ }
+ }
+ }
+ *p = '\0';
+ return Jim_NewStringObjNoAlloc(interp, bytes, len);
+ }
+}
+
+Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ int len, rangeLen;
+
+ if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+ Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+ return NULL;
+ len = Jim_ListLength(interp, listObjPtr);
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+ if (first == 0 && last == len) {
+ return listObjPtr;
+ }
+ return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
+}
+
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfDict(struct Jim_Obj *objPtr);
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+
+static const Jim_ObjType dictObjType = {
+ "dict",
+ FreeDictInternalRep,
+ DupDictInternalRep,
+ UpdateStringOfDict,
+ JIM_TYPE_NONE,
+};
+
+static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
+{
+ int i;
+ for (i = 0; i < dict->len; i++) {
+ Jim_DecrRefCount(interp, dict->table[i]);
+ }
+ Jim_Free(dict->table);
+ Jim_Free(dict->ht);
+ Jim_Free(dict);
+}
+
+enum {
+ DICT_HASH_FIND = -1,
+ DICT_HASH_REMOVE = -2,
+ DICT_HASH_ADD = -3,
+};
+
+static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
+{
+ unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
+ unsigned idx = h & dict->sizemask;
+ int tvoffset = 0;
+ unsigned peturb = h;
+ unsigned first_removed = ~0;
+
+ if (dict->len) {
+ while ((tvoffset = dict->ht[idx].offset)) {
+ if (tvoffset == -1) {
+ if (first_removed == ~0) {
+ first_removed = idx;
+ }
+ }
+ else if (dict->ht[idx].hash == h) {
+ if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
+ break;
+ }
+ }
+
+ peturb >>= 5;
+ idx = (5 * idx + 1 + peturb) & dict->sizemask;
+ }
+ }
+
+ switch (op_tvoffset) {
+ case DICT_HASH_FIND:
+
+ break;
+ case DICT_HASH_REMOVE:
+ if (tvoffset) {
+
+ dict->ht[idx].offset = -1;
+ dict->dummy++;
+ }
+
+ break;
+ case DICT_HASH_ADD:
+ if (tvoffset == 0) {
+
+ if (first_removed != ~0) {
+ idx = first_removed;
+ dict->dummy--;
+ }
+ dict->ht[idx].offset = dict->len + 1;
+ dict->ht[idx].hash = h;
+ }
+
+ break;
+ default:
+ assert(tvoffset);
+
+ dict->ht[idx].offset = op_tvoffset;
+ break;
+ }
+
+ return tvoffset;
+}
+
+static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
+{
+ int i;
+ struct JimDictHashEntry *prevht = dict->ht;
+ int prevsize = dict->size;
+
+ dict->size = JimHashTableNextPower(size);
+ dict->sizemask = dict->size - 1;
+
+
+ dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
+ memset(dict->ht, 0, dict->size * sizeof(*dict->ht));
+
+
+ for (i = 0; i < prevsize; i++) {
+ if (prevht[i].offset > 0) {
+
+ unsigned h = prevht[i].hash;
+ unsigned idx = h & dict->sizemask;
+ unsigned peturb = h;
+
+ while (dict->ht[idx].offset) {
+ peturb >>= 5;
+ idx = (5 * idx + 1 + peturb) & dict->sizemask;
+ }
+ dict->ht[idx].offset = prevht[i].offset;
+ dict->ht[idx].hash = h;
+ }
+ }
+ Jim_Free(prevht);
+}
+
+static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
+{
+ if (dict->size <= dict->len + dict->dummy) {
+ JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
+ }
+ return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
+}
+
+static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
+{
+ Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
+ memset(dict, 0, sizeof(*dict));
+
+ if (ht_size) {
+ JimDictExpandHashTable(dict, ht_size);
+ }
+ if (table_size) {
+ dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
+ dict->maxLen = table_size;
+ }
+#ifdef JIM_RANDOMISE_HASH
+ dict->uniq = (rand() ^ time(NULL) ^ clock());
+#endif
+ return dict;
+}
+
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JimFreeDict(interp, objPtr->internalRep.dictValue);
+}
+
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
+ int i;
+
+
+ Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);
+
+
+ for (i = 0; i < oldDict->len; i++) {
+ newDict->table[i] = oldDict->table[i];
+ Jim_IncrRefCount(newDict->table[i]);
+ }
+ newDict->len = oldDict->len;
+
+
+ newDict->uniq = oldDict->uniq;
+
+
+ memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
+
+ dupPtr->internalRep.dictValue = newDict;
+ dupPtr->typePtr = &dictObjType;
+}
+
+static void UpdateStringOfDict(struct Jim_Obj *objPtr)
+{
+ JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
+}
+
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int listlen;
+
+ if (objPtr->typePtr == &dictObjType) {
+ return JIM_OK;
+ }
+
+ if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
+ Jim_String(objPtr);
+ }
+
+ listlen = Jim_ListLength(interp, objPtr);
+ if (listlen % 2) {
+ Jim_SetResultString(interp, "missing value to go with key", -1);
+ return JIM_ERR;
+ }
+ else {
+
+ Jim_Dict *dict = JimDictNew(interp, 0, listlen);
+ int i;
+
+
+ dict->table = objPtr->internalRep.listValue.ele;
+ dict->maxLen = objPtr->internalRep.listValue.maxLen;
+
+
+ for (i = 0; i < listlen; i += 2) {
+ int tvoffset = JimDictAdd(dict, dict->table[i]);
+ if (tvoffset) {
+
+
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+
+ dict->table[tvoffset] = dict->table[i + 1];
+
+ Jim_DecrRefCount(interp, dict->table[i]);
+ }
+ else {
+ if (dict->len != i) {
+ dict->table[dict->len++] = dict->table[i];
+ dict->table[dict->len++] = dict->table[i + 1];
+ }
+ else {
+ dict->len += 2;
+ }
+ }
+ }
+
+ objPtr->typePtr = &dictObjType;
+ objPtr->internalRep.dictValue = dict;
+
+ return JIM_OK;
+ }
+}
+
+
+
+static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ Jim_Dict *dict = objPtr->internalRep.dictValue;
+ if (valueObjPtr == NULL) {
+
+ int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
+ if (tvoffset) {
+
+ Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+ dict->len -= 2;
+ if (tvoffset != dict->len + 1) {
+
+ dict->table[tvoffset - 1] = dict->table[dict->len];
+ dict->table[tvoffset] = dict->table[dict->len + 1];
+
+
+ JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
+ }
+ return JIM_OK;
+ }
+ return JIM_ERR;
+ }
+ else {
+
+ int tvoffset = JimDictAdd(dict, keyObjPtr);
+ if (tvoffset) {
+
+ Jim_IncrRefCount(valueObjPtr);
+ Jim_DecrRefCount(interp, dict->table[tvoffset]);
+ dict->table[tvoffset] = valueObjPtr;
+ }
+ else {
+ if (dict->maxLen == dict->len) {
+
+ if (dict->maxLen < 4) {
+ dict->maxLen = 4;
+ }
+ else {
+ dict->maxLen *= 2;
+ }
+ dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
+ }
+ Jim_IncrRefCount(keyObjPtr);
+ Jim_IncrRefCount(valueObjPtr);
+
+ dict->table[dict->len++] = keyObjPtr;
+ dict->table[dict->len++] = valueObjPtr;
+
+ }
+ return JIM_OK;
+ }
+}
+
+int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_InvalidateStringRep(objPtr);
+ return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
+}
+
+Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+ int i;
+
+ JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &dictObjType;
+ objPtr->bytes = NULL;
+
+ objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
+ for (i = 0; i < len; i += 2)
+ DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
+ return objPtr;
+}
+
+int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
+ Jim_Obj **objPtrPtr, int flags)
+{
+ int tvoffset;
+ Jim_Dict *dict;
+
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+ return -1;
+ }
+ dict = dictPtr->internalRep.dictValue;
+ tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
+ if (tvoffset == 0) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
+ }
+ return JIM_ERR;
+ }
+ *objPtrPtr = dict->table[tvoffset];
+ return JIM_OK;
+}
+
+Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
+{
+
+ if (Jim_IsList(dictPtr)) {
+ Jim_Obj **table;
+ JimListGetElements(interp, dictPtr, len, &table);
+ if (*len % 2 == 0) {
+ return table;
+ }
+
+ }
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+
+ *len = 1;
+ return NULL;
+ }
+ *len = dictPtr->internalRep.dictValue->len;
+ return dictPtr->internalRep.dictValue->table;
+}
+
+
+int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
+{
+ int i;
+
+ if (keyc == 0) {
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+ }
+
+ for (i = 0; i < keyc; i++) {
+ Jim_Obj *objPtr;
+
+ int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
+ if (rc != JIM_OK) {
+ return rc;
+ }
+ dictPtr = objPtr;
+ }
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+}
+
+int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
+{
+ Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
+ int shared, i;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
+ if (objPtr == NULL) {
+ if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
+
+ return JIM_ERR;
+ }
+ varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
+ if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ return JIM_ERR;
+ }
+ }
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < keyc; i++) {
+ dictObjPtr = objPtr;
+
+
+ if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+ if (i == keyc - 1) {
+
+ if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
+ if (newObjPtr || (flags & JIM_MUSTEXIST)) {
+ goto err;
+ }
+ }
+ break;
+ }
+
+
+ Jim_InvalidateStringRep(dictObjPtr);
+ if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
+ newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+ else {
+ if (newObjPtr == NULL) {
+ goto err;
+ }
+ objPtr = Jim_NewDictObj(interp, NULL, 0);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+ if (!(flags & JIM_NORESULT)) {
+ Jim_SetResult(interp, varObjPtr);
+ }
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
+static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType indexObjType = {
+ "index",
+ NULL,
+ NULL,
+ UpdateStringOfIndex,
+ JIM_TYPE_NONE,
+};
+
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
+{
+ if (objPtr->internalRep.intValue == -1) {
+ JimSetStringBytes(objPtr, "end");
+ }
+ else {
+ char buf[JIM_INTEGER_SPACE + 1];
+ if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
+ sprintf(buf, "%d", objPtr->internalRep.intValue);
+ }
+ else {
+
+ sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
+ }
+ JimSetStringBytes(objPtr, buf);
+ }
+}
+
+static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ jim_wide idx;
+ int end = 0;
+ const char *str;
+ Jim_Obj *exprObj = objPtr;
+
+ JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
+
+
+ str = Jim_String(objPtr);
+
+
+ if (strncmp(str, "end", 3) == 0) {
+ end = 1;
+ str += 3;
+ idx = 0;
+ switch (*str) {
+ case '\0':
+ exprObj = NULL;
+ break;
+
+ case '-':
+ case '+':
+ exprObj = Jim_NewStringObj(interp, str, -1);
+ break;
+
+ default:
+ goto badindex;
+ }
+ }
+ if (exprObj) {
+ int ret;
+ Jim_IncrRefCount(exprObj);
+ ret = Jim_GetWideExpr(interp, exprObj, &idx);
+ Jim_DecrRefCount(interp, exprObj);
+ if (ret != JIM_OK) {
+ goto badindex;
+ }
+ }
+
+ if (end) {
+ if (idx > 0) {
+ idx = INT_MAX;
+ }
+ else {
+
+ idx--;
+ }
+ }
+ else if (idx < 0) {
+ idx = -INT_MAX;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &indexObjType;
+ objPtr->internalRep.intValue = idx;
+ return JIM_OK;
+
+ badindex:
+ Jim_SetResultFormatted(interp,
+ "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
+ return JIM_ERR;
+}
+
+int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
+{
+
+ if (objPtr->typePtr == &intObjType) {
+ jim_wide val = JimWideValue(objPtr);
+
+ if (val < 0)
+ *indexPtr = -INT_MAX;
+ else if (val > INT_MAX)
+ *indexPtr = INT_MAX;
+ else
+ *indexPtr = (int)val;
+ return JIM_OK;
+ }
+ if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *indexPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+
+
+static const char * const jimReturnCodes[] = {
+ "ok",
+ "error",
+ "return",
+ "break",
+ "continue",
+ "signal",
+ "exit",
+ "eval",
+ NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
+
+static const Jim_ObjType returnCodeObjType = {
+ "return-code",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+const char *Jim_ReturnCode(int code)
+{
+ if (code < 0 || code >= (int)jimReturnCodesSize) {
+ return "?";
+ }
+ else {
+ return jimReturnCodes[code];
+ }
+}
+
+static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int returnCode;
+ jim_wide wideValue;
+
+
+ if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
+ returnCode = (int)wideValue;
+ else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &returnCodeObjType;
+ objPtr->internalRep.intValue = returnCode;
+ return JIM_OK;
+}
+
+int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
+{
+ if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *intPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc);
+static int JimParseExprNumber(struct JimParserCtx *pc);
+static int JimParseExprIrrational(struct JimParserCtx *pc);
+static int JimParseExprBoolean(struct JimParserCtx *pc);
+
+
+enum
+{
+
+
+
+ JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
+ JIM_EXPROP_DIV,
+ JIM_EXPROP_MOD,
+ JIM_EXPROP_SUB,
+ JIM_EXPROP_ADD,
+ JIM_EXPROP_LSHIFT,
+ JIM_EXPROP_RSHIFT,
+ JIM_EXPROP_ROTL,
+ JIM_EXPROP_ROTR,
+ JIM_EXPROP_LT,
+ JIM_EXPROP_GT,
+ JIM_EXPROP_LTE,
+ JIM_EXPROP_GTE,
+ JIM_EXPROP_NUMEQ,
+ JIM_EXPROP_NUMNE,
+ JIM_EXPROP_BITAND,
+ JIM_EXPROP_BITXOR,
+ JIM_EXPROP_BITOR,
+ JIM_EXPROP_LOGICAND,
+ JIM_EXPROP_LOGICOR,
+ JIM_EXPROP_TERNARY,
+ JIM_EXPROP_COLON,
+ JIM_EXPROP_POW,
+
+
+ JIM_EXPROP_STREQ,
+ JIM_EXPROP_STRNE,
+ JIM_EXPROP_STRIN,
+ JIM_EXPROP_STRNI,
+ JIM_EXPROP_STRLT,
+ JIM_EXPROP_STRGT,
+ JIM_EXPROP_STRLE,
+ JIM_EXPROP_STRGE,
+
+
+ JIM_EXPROP_NOT,
+ JIM_EXPROP_BITNOT,
+ JIM_EXPROP_UNARYMINUS,
+ JIM_EXPROP_UNARYPLUS,
+
+
+ JIM_EXPROP_FUNC_INT,
+ JIM_EXPROP_FUNC_WIDE,
+ JIM_EXPROP_FUNC_ABS,
+ JIM_EXPROP_FUNC_DOUBLE,
+ JIM_EXPROP_FUNC_ROUND,
+ JIM_EXPROP_FUNC_RAND,
+ JIM_EXPROP_FUNC_SRAND,
+
+
+ JIM_EXPROP_FUNC_SIN,
+ JIM_EXPROP_FUNC_COS,
+ JIM_EXPROP_FUNC_TAN,
+ JIM_EXPROP_FUNC_ASIN,
+ JIM_EXPROP_FUNC_ACOS,
+ JIM_EXPROP_FUNC_ATAN,
+ JIM_EXPROP_FUNC_ATAN2,
+ JIM_EXPROP_FUNC_SINH,
+ JIM_EXPROP_FUNC_COSH,
+ JIM_EXPROP_FUNC_TANH,
+ JIM_EXPROP_FUNC_CEIL,
+ JIM_EXPROP_FUNC_FLOOR,
+ JIM_EXPROP_FUNC_EXP,
+ JIM_EXPROP_FUNC_LOG,
+ JIM_EXPROP_FUNC_LOG10,
+ JIM_EXPROP_FUNC_SQRT,
+ JIM_EXPROP_FUNC_POW,
+ JIM_EXPROP_FUNC_HYPOT,
+ JIM_EXPROP_FUNC_FMOD,
+};
+
+struct JimExprNode {
+ int type;
+ struct Jim_Obj *objPtr;
+
+ struct JimExprNode *left;
+ struct JimExprNode *right;
+ struct JimExprNode *ternary;
+};
+
+
+typedef struct Jim_ExprOperator
+{
+ const char *name;
+ int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
+ unsigned char precedence;
+ unsigned char arity;
+ unsigned char attr;
+ unsigned char namelen;
+} Jim_ExprOperator;
+
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
+
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int intresult = 1;
+ int rc, bA = 0;
+ double dA, dC = 0;
+ jim_wide wA, wC = 0;
+ Jim_Obj *A;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_INT:
+ case JIM_EXPROP_FUNC_WIDE:
+ case JIM_EXPROP_FUNC_ROUND:
+ case JIM_EXPROP_UNARYPLUS:
+ wC = wA;
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ dC = wA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+ wC = wA >= 0 ? wA : -wA;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ wC = -wA;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !wA;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_INT:
+ case JIM_EXPROP_FUNC_WIDE:
+ wC = dA;
+ break;
+ case JIM_EXPROP_FUNC_ROUND:
+ wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ case JIM_EXPROP_UNARYPLUS:
+ dC = dA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+#ifdef JIM_MATH_FUNCTIONS
+ dC = fabs(dA);
+#else
+ dC = dA >= 0 ? dA : -dA;
+#endif
+ intresult = 0;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ dC = -dA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !dA;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_NOT:
+ wC = !bA;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (rc == JIM_OK) {
+ if (intresult) {
+ Jim_SetResultInt(interp, wC);
+ }
+ else {
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static double JimRandDouble(Jim_Interp *interp)
+{
+ unsigned long x;
+ JimRandomBytes(interp, &x, sizeof(x));
+
+ return (double)x / (double)~0UL;
+}
+
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ jim_wide wA;
+ Jim_Obj *A;
+ int rc;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ rc = Jim_GetWide(interp, A, &wA);
+ if (rc == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_BITNOT:
+ Jim_SetResultInt(interp, ~wA);
+ break;
+ case JIM_EXPROP_FUNC_SRAND:
+ JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+ break;
+ default:
+ abort();
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
+{
+ JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
+
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+
+ return JIM_OK;
+}
+
+#ifdef JIM_MATH_FUNCTIONS
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int rc;
+ double dA, dC;
+ Jim_Obj *A;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+
+ rc = Jim_GetDouble(interp, A, &dA);
+ if (rc == JIM_OK) {
+ switch (node->type) {
+ case JIM_EXPROP_FUNC_SIN:
+ dC = sin(dA);
+ break;
+ case JIM_EXPROP_FUNC_COS:
+ dC = cos(dA);
+ break;
+ case JIM_EXPROP_FUNC_TAN:
+ dC = tan(dA);
+ break;
+ case JIM_EXPROP_FUNC_ASIN:
+ dC = asin(dA);
+ break;
+ case JIM_EXPROP_FUNC_ACOS:
+ dC = acos(dA);
+ break;
+ case JIM_EXPROP_FUNC_ATAN:
+ dC = atan(dA);
+ break;
+ case JIM_EXPROP_FUNC_SINH:
+ dC = sinh(dA);
+ break;
+ case JIM_EXPROP_FUNC_COSH:
+ dC = cosh(dA);
+ break;
+ case JIM_EXPROP_FUNC_TANH:
+ dC = tanh(dA);
+ break;
+ case JIM_EXPROP_FUNC_CEIL:
+ dC = ceil(dA);
+ break;
+ case JIM_EXPROP_FUNC_FLOOR:
+ dC = floor(dA);
+ break;
+ case JIM_EXPROP_FUNC_EXP:
+ dC = exp(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG:
+ dC = log(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG10:
+ dC = log10(dA);
+ break;
+ case JIM_EXPROP_FUNC_SQRT:
+ dC = sqrt(dA);
+ break;
+ default:
+ abort();
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+#endif
+
+
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ jim_wide wA, wB;
+ int rc;
+ Jim_Obj *A, *B;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ rc = JIM_ERR;
+
+ if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+ jim_wide wC;
+
+ rc = JIM_OK;
+
+ switch (node->type) {
+ case JIM_EXPROP_LSHIFT:
+ wC = wA << wB;
+ break;
+ case JIM_EXPROP_RSHIFT:
+ wC = wA >> wB;
+ break;
+ case JIM_EXPROP_BITAND:
+ wC = wA & wB;
+ break;
+ case JIM_EXPROP_BITXOR:
+ wC = wA ^ wB;
+ break;
+ case JIM_EXPROP_BITOR:
+ wC = wA | wB;
+ break;
+ case JIM_EXPROP_MOD:
+ if (wB == 0) {
+ wC = 0;
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ int negative = 0;
+
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ negative = 1;
+ }
+ wC = wA % wB;
+ if (wC < 0) {
+ wC += wB;
+ }
+ if (negative) {
+ wC = -wC;
+ }
+ }
+ break;
+ case JIM_EXPROP_ROTL:
+ case JIM_EXPROP_ROTR:{
+
+ unsigned long uA = (unsigned long)wA;
+ unsigned long uB = (unsigned long)wB;
+ const unsigned int S = sizeof(unsigned long) * 8;
+
+
+ uB %= S;
+
+ if (node->type == JIM_EXPROP_ROTR) {
+ uB = S - uB;
+ }
+ wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
+ break;
+ }
+ default:
+ abort();
+ }
+ Jim_SetResultInt(interp, wC);
+ }
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+
+
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ int rc = JIM_OK;
+ double dA, dB, dC = 0;
+ jim_wide wA, wB, wC = 0;
+ Jim_Obj *A, *B;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ if ((A->typePtr != &doubleObjType || A->bytes) &&
+ (B->typePtr != &doubleObjType || B->bytes) &&
+ JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+
+
+
+ switch (node->type) {
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ if (wA == 0 && wB < 0) {
+ Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
+ rc = JIM_ERR;
+ goto done;
+ }
+ wC = JimPowWide(wA, wB);
+ goto intresult;
+ case JIM_EXPROP_ADD:
+ wC = wA + wB;
+ goto intresult;
+ case JIM_EXPROP_SUB:
+ wC = wA - wB;
+ goto intresult;
+ case JIM_EXPROP_MUL:
+ wC = wA * wB;
+ goto intresult;
+ case JIM_EXPROP_DIV:
+ if (wB == 0) {
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ goto done;
+ }
+ else {
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ }
+ wC = wA / wB;
+ if (wA % wB < 0) {
+ wC--;
+ }
+ goto intresult;
+ }
+ case JIM_EXPROP_LT:
+ wC = wA < wB;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = wA > wB;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = wA <= wB;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = wA >= wB;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = wA == wB;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = wA != wB;
+ goto intresult;
+ }
+ }
+ if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+ switch (node->type) {
+#ifndef JIM_MATH_FUNCTIONS
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ case JIM_EXPROP_FUNC_ATAN2:
+ case JIM_EXPROP_FUNC_HYPOT:
+ case JIM_EXPROP_FUNC_FMOD:
+ Jim_SetResultString(interp, "unsupported", -1);
+ rc = JIM_ERR;
+ goto done;
+#else
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ dC = pow(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_ATAN2:
+ dC = atan2(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_HYPOT:
+ dC = hypot(dA, dB);
+ goto doubleresult;
+ case JIM_EXPROP_FUNC_FMOD:
+ dC = fmod(dA, dB);
+ goto doubleresult;
+#endif
+ case JIM_EXPROP_ADD:
+ dC = dA + dB;
+ goto doubleresult;
+ case JIM_EXPROP_SUB:
+ dC = dA - dB;
+ goto doubleresult;
+ case JIM_EXPROP_MUL:
+ dC = dA * dB;
+ goto doubleresult;
+ case JIM_EXPROP_DIV:
+ if (dB == 0) {
+#ifdef INFINITY
+ dC = dA < 0 ? -INFINITY : INFINITY;
+#else
+ dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
+#endif
+ }
+ else {
+ dC = dA / dB;
+ }
+ goto doubleresult;
+ case JIM_EXPROP_LT:
+ wC = dA < dB;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = dA > dB;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = dA <= dB;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = dA >= dB;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = dA == dB;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = dA != dB;
+ goto intresult;
+ }
+ }
+ else {
+
+
+
+ int i = Jim_StringCompareObj(interp, A, B, 0);
+
+ switch (node->type) {
+ case JIM_EXPROP_LT:
+ wC = i < 0;
+ goto intresult;
+ case JIM_EXPROP_GT:
+ wC = i > 0;
+ goto intresult;
+ case JIM_EXPROP_LTE:
+ wC = i <= 0;
+ goto intresult;
+ case JIM_EXPROP_GTE:
+ wC = i >= 0;
+ goto intresult;
+ case JIM_EXPROP_NUMEQ:
+ wC = i == 0;
+ goto intresult;
+ case JIM_EXPROP_NUMNE:
+ wC = i != 0;
+ goto intresult;
+ }
+ }
+
+ rc = JIM_ERR;
+done:
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+ return rc;
+intresult:
+ Jim_SetResultInt(interp, wC);
+ goto done;
+doubleresult:
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
+ goto done;
+}
+
+static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
+{
+ int listlen;
+ int i;
+
+ listlen = Jim_ListLength(interp, listObjPtr);
+ for (i = 0; i < listlen; i++) {
+ if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
+{
+ Jim_Obj *A, *B;
+ jim_wide wC;
+ int comp, rc;
+
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
+ return rc;
+ }
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
+ Jim_DecrRefCount(interp, A);
+ return rc;
+ }
+
+ switch (node->type) {
+ case JIM_EXPROP_STREQ:
+ case JIM_EXPROP_STRNE:
+ wC = Jim_StringEqObj(A, B);
+ if (node->type == JIM_EXPROP_STRNE) {
+ wC = !wC;
+ }
+ break;
+ case JIM_EXPROP_STRLT:
+ case JIM_EXPROP_STRGT:
+ case JIM_EXPROP_STRLE:
+ case JIM_EXPROP_STRGE:
+ comp = Jim_StringCompareObj(interp, A, B, 0);
+ if (node->type == JIM_EXPROP_STRLT) {
+ wC = comp == -1;
+ } else if (node->type == JIM_EXPROP_STRGT) {
+ wC = comp == 1;
+ } else if (node->type == JIM_EXPROP_STRLE) {
+ wC = comp == -1 || comp == 0;
+ } else {
+ wC = comp == 0 || comp == 1;
+ }
+ break;
+ case JIM_EXPROP_STRIN:
+ wC = JimSearchList(interp, B, A);
+ break;
+ case JIM_EXPROP_STRNI:
+ wC = !JimSearchList(interp, B, A);
+ break;
+ default:
+ abort();
+ }
+ Jim_SetResultInt(interp, wC);
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
+{
+ long l;
+ double d;
+ int b;
+ int ret = -1;
+
+
+ Jim_IncrRefCount(obj);
+
+ if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+ ret = (l != 0);
+ }
+ else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+ ret = (d != 0);
+ }
+ else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
+ ret = (b != 0);
+ }
+
+ Jim_DecrRefCount(interp, obj);
+ return ret;
+}
+
+static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 1) {
+
+ result = JimExprGetTermBoolean(interp, node->right);
+ }
+ if (result == -1) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, result);
+ return JIM_OK;
+}
+
+static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 0) {
+
+ result = JimExprGetTermBoolean(interp, node->right);
+ }
+ if (result == -1) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, result);
+ return JIM_OK;
+}
+
+static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
+{
+
+ int result = JimExprGetTermBoolean(interp, node->left);
+
+ if (result == 1) {
+
+ return JimExprEvalTermNode(interp, node->right);
+ }
+ else if (result == 0) {
+
+ return JimExprEvalTermNode(interp, node->ternary);
+ }
+
+ return JIM_ERR;
+}
+
+enum
+{
+ OP_FUNC = 0x0001,
+ OP_RIGHT_ASSOC = 0x0002,
+};
+
+#define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
+#define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
+
+static const struct Jim_ExprOperator Jim_ExprOperators[] = {
+ OPRINIT("*", 110, 2, JimExprOpBin),
+ OPRINIT("/", 110, 2, JimExprOpBin),
+ OPRINIT("%", 110, 2, JimExprOpIntBin),
+
+ OPRINIT("-", 100, 2, JimExprOpBin),
+ OPRINIT("+", 100, 2, JimExprOpBin),
+
+ OPRINIT("<<", 90, 2, JimExprOpIntBin),
+ OPRINIT(">>", 90, 2, JimExprOpIntBin),
+
+ OPRINIT("<<<", 90, 2, JimExprOpIntBin),
+ OPRINIT(">>>", 90, 2, JimExprOpIntBin),
+
+ OPRINIT("<", 80, 2, JimExprOpBin),
+ OPRINIT(">", 80, 2, JimExprOpBin),
+ OPRINIT("<=", 80, 2, JimExprOpBin),
+ OPRINIT(">=", 80, 2, JimExprOpBin),
+
+ OPRINIT("==", 70, 2, JimExprOpBin),
+ OPRINIT("!=", 70, 2, JimExprOpBin),
+
+ OPRINIT("&", 50, 2, JimExprOpIntBin),
+ OPRINIT("^", 49, 2, JimExprOpIntBin),
+ OPRINIT("|", 48, 2, JimExprOpIntBin),
+
+ OPRINIT("&&", 10, 2, JimExprOpAnd),
+ OPRINIT("||", 9, 2, JimExprOpOr),
+ OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
+
+
+ OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
+
+ OPRINIT("eq", 60, 2, JimExprOpStrBin),
+ OPRINIT("ne", 60, 2, JimExprOpStrBin),
+
+ OPRINIT("in", 55, 2, JimExprOpStrBin),
+ OPRINIT("ni", 55, 2, JimExprOpStrBin),
+
+ OPRINIT("lt", 75, 2, JimExprOpStrBin),
+ OPRINIT("gt", 75, 2, JimExprOpStrBin),
+ OPRINIT("le", 75, 2, JimExprOpStrBin),
+ OPRINIT("ge", 75, 2, JimExprOpStrBin),
+
+ OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+ OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
+
+
+
+ OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
+ OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
+ OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
+
+#ifdef JIM_MATH_FUNCTIONS
+ OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
+ OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
+ OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
+#endif
+};
+#undef OPRINIT
+#undef OPRINIT_ATTR
+
+#define JIM_EXPR_OPERATORS_NUM \
+ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
+
+static int JimParseExpression(struct JimParserCtx *pc)
+{
+ pc->errmsg = NULL;
+
+ while (1) {
+
+ while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ if (*pc->p == '#') {
+ JimParseComment(pc);
+
+ continue;
+ }
+ break;
+ }
+
+
+ pc->tline = pc->linenr;
+ pc->tstart = pc->p;
+
+ if (pc->len == 0) {
+ pc->tend = pc->p;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '(':
+ pc->tt = JIM_TT_SUBEXPR_START;
+ goto singlechar;
+ case ')':
+ pc->tt = JIM_TT_SUBEXPR_END;
+ goto singlechar;
+ case ',':
+ pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
+ pc->tend = pc->p;
+ pc->p++;
+ pc->len--;
+ break;
+ case '[':
+ return JimParseCmd(pc);
+ case '$':
+ if (JimParseVar(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ else {
+
+ if (pc->tt == JIM_TT_EXPRSUGAR) {
+ pc->errmsg = "nesting expr in expr is not allowed";
+ return JIM_ERR;
+ }
+ return JIM_OK;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ return JimParseExprNumber(pc);
+ case '"':
+ return JimParseQuote(pc);
+ case '{':
+ return JimParseBrace(pc);
+
+ case 'N':
+ case 'I':
+ case 'n':
+ case 'i':
+ if (JimParseExprIrrational(pc) == JIM_ERR)
+ if (JimParseExprBoolean(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ break;
+ case 't':
+ case 'f':
+ case 'o':
+ case 'y':
+ if (JimParseExprBoolean(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ break;
+ default:
+ return JimParseExprOperator(pc);
+ break;
+ }
+ return JIM_OK;
+}
+
+static int JimParseExprNumber(struct JimParserCtx *pc)
+{
+ char *end;
+
+
+ pc->tt = JIM_TT_EXPR_INT;
+
+ jim_strtoull(pc->p, (char **)&pc->p);
+
+ if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
+ if (strtod(pc->tstart, &end)) { }
+ if (end == pc->tstart)
+ return JIM_ERR;
+ if (end > pc->p) {
+
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ pc->p = end;
+ }
+ }
+ pc->tend = pc->p - 1;
+ pc->len -= (pc->p - pc->tstart);
+ return JIM_OK;
+}
+
+static int JimParseExprIrrational(struct JimParserCtx *pc)
+{
+ const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
+ int i;
+
+ for (i = 0; irrationals[i]; i++) {
+ const char *irr = irrationals[i];
+
+ if (strncmp(irr, pc->p, 3) == 0) {
+ pc->p += 3;
+ pc->len -= 3;
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ return JIM_OK;
+ }
+ }
+ return JIM_ERR;
+}
+
+static int JimParseExprBoolean(struct JimParserCtx *pc)
+{
+ int i;
+ for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
+ if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
+ pc->p += jim_true_false_lens[i];
+ pc->len -= jim_true_false_lens[i];
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EXPR_BOOLEAN;
+ return JIM_OK;
+ }
+ }
+ return JIM_ERR;
+}
+
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
+{
+ static Jim_ExprOperator dummy_op;
+ if (opcode < JIM_TT_EXPR_OP) {
+ return &dummy_op;
+ }
+ return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc)
+{
+ int i;
+ const struct Jim_ExprOperator *bestOp = NULL;
+ int bestLen = 0;
+
+
+ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+ const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
+
+ if (op->name[0] != pc->p[0]) {
+ continue;
+ }
+
+ if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
+ bestOp = op;
+ bestLen = op->namelen;
+ }
+ }
+ if (bestOp == NULL) {
+ return JIM_ERR;
+ }
+
+
+ if (bestOp->attr & OP_FUNC) {
+ const char *p = pc->p + bestLen;
+ int len = pc->len - bestLen;
+
+ while (len && isspace(UCHAR(*p))) {
+ len--;
+ p++;
+ }
+ if (*p != '(') {
+ pc->errmsg = "function requires parentheses";
+ return JIM_ERR;
+ }
+ }
+ pc->tend = pc->p + bestLen - 1;
+ pc->p += bestLen;
+ pc->len -= bestLen;
+
+ pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
+ return JIM_OK;
+}
+
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType exprObjType = {
+ "expression",
+ FreeExprInternalRep,
+ DupExprInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+
+struct ExprTree
+{
+ struct JimExprNode *expr;
+ struct JimExprNode *nodes;
+ int len;
+ int inUse;
+};
+
+static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
+{
+ int i;
+ for (i = 0; i < num; i++) {
+ if (nodes[i].objPtr) {
+ Jim_DecrRefCount(interp, nodes[i].objPtr);
+ }
+ }
+ Jim_Free(nodes);
+}
+
+static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
+{
+ ExprTreeFreeNodes(interp, expr->nodes, expr->len);
+ Jim_Free(expr);
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
+
+ if (expr) {
+ if (--expr->inUse != 0) {
+ return;
+ }
+
+ ExprTreeFree(interp, expr);
+ }
+}
+
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+
+ dupPtr->typePtr = NULL;
+}
+
+struct ExprBuilder {
+ int parencount;
+ int level;
+ ParseToken *token;
+ ParseToken *first_token;
+ Jim_Stack stack;
+ Jim_Obj *exprObjPtr;
+ Jim_Obj *fileNameObj;
+ struct JimExprNode *nodes;
+ struct JimExprNode *next;
+};
+
+#ifdef DEBUG_SHOW_EXPR
+static void JimShowExprNode(struct JimExprNode *node, int level)
+{
+ int i;
+ for (i = 0; i < level; i++) {
+ printf(" ");
+ }
+ if (TOKEN_IS_EXPR_OP(node->type)) {
+ printf("%s\n", jim_tt_name(node->type));
+ if (node->left) {
+ JimShowExprNode(node->left, level + 1);
+ }
+ if (node->right) {
+ JimShowExprNode(node->right, level + 1);
+ }
+ if (node->ternary) {
+ JimShowExprNode(node->ternary, level + 1);
+ }
+ }
+ else {
+ printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
+ }
+}
+#endif
+
+#define EXPR_UNTIL_CLOSE 0x0001
+#define EXPR_FUNC_ARGS 0x0002
+#define EXPR_TERNARY 0x0004
+
+static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
+ int rc;
+ struct JimExprNode *node;
+
+ int exp_stacklen = builder->stack.len + exp_numterms;
+
+ if (builder->level++ > 200) {
+ Jim_SetResultString(interp, "Expression too complex", -1);
+ return JIM_ERR;
+ }
+
+ while (builder->token->type != JIM_TT_EOL) {
+ ParseToken *t = builder->token++;
+ int prevtt;
+
+ if (t == builder->first_token) {
+ prevtt = JIM_TT_NONE;
+ }
+ else {
+ prevtt = t[-1].type;
+ }
+
+ if (t->type == JIM_TT_SUBEXPR_START) {
+ if (builder->stack.len == exp_stacklen) {
+ Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ builder->parencount++;
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
+ if (rc != JIM_OK) {
+ return rc;
+ }
+
+ }
+ else if (t->type == JIM_TT_SUBEXPR_END) {
+ if (!(flags & EXPR_UNTIL_CLOSE)) {
+ if (builder->stack.len == exp_stacklen && builder->level > 1) {
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ builder->parencount--;
+ if (builder->stack.len == exp_stacklen) {
+
+ break;
+ }
+ }
+ else if (t->type == JIM_TT_SUBEXPR_COMMA) {
+ if (!(flags & EXPR_FUNC_ARGS)) {
+ if (builder->stack.len == exp_stacklen) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ else {
+
+ if (builder->stack.len > exp_stacklen) {
+ Jim_SetResultFormatted(interp, "too many arguments to math function");
+ return JIM_ERR;
+ }
+ }
+
+ }
+ else if (t->type == JIM_EXPROP_COLON) {
+ if (!(flags & EXPR_TERNARY)) {
+ if (builder->level != 1) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+ Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+ if (builder->stack.len == exp_stacklen) {
+
+ builder->token--;
+ builder->level--;
+ return JIM_OK;
+ }
+
+ }
+ else if (TOKEN_IS_EXPR_OP(t->type)) {
+ const struct Jim_ExprOperator *op;
+
+
+ if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
+ if (t->type == JIM_EXPROP_SUB) {
+ t->type = JIM_EXPROP_UNARYMINUS;
+ }
+ else if (t->type == JIM_EXPROP_ADD) {
+ t->type = JIM_EXPROP_UNARYPLUS;
+ }
+ }
+
+ op = JimExprOperatorInfoByOpcode(t->type);
+
+ if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
+
+ builder->token--;
+ break;
+ }
+
+ if (op->attr & OP_FUNC) {
+ if (builder->token->type != JIM_TT_SUBEXPR_START) {
+ Jim_SetResultString(interp, "missing arguments for math function", -1);
+ return JIM_ERR;
+ }
+ builder->token++;
+ if (op->arity == 0) {
+ if (builder->token->type != JIM_TT_SUBEXPR_END) {
+ Jim_SetResultString(interp, "too many arguments for math function", -1);
+ return JIM_ERR;
+ }
+ builder->token++;
+ goto noargs;
+ }
+ builder->parencount++;
+
+
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
+ }
+ else if (t->type == JIM_EXPROP_TERNARY) {
+
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
+ }
+ else {
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
+ }
+
+ if (rc != JIM_OK) {
+ return rc;
+ }
+
+noargs:
+ node = builder->next++;
+ node->type = t->type;
+
+ if (op->arity >= 3) {
+ node->ternary = Jim_StackPop(&builder->stack);
+ if (node->ternary == NULL) {
+ goto missingoperand;
+ }
+ }
+ if (op->arity >= 2) {
+ node->right = Jim_StackPop(&builder->stack);
+ if (node->right == NULL) {
+ goto missingoperand;
+ }
+ }
+ if (op->arity >= 1) {
+ node->left = Jim_StackPop(&builder->stack);
+ if (node->left == NULL) {
+missingoperand:
+ Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
+ builder->next--;
+ return JIM_ERR;
+
+ }
+ }
+
+
+ Jim_StackPush(&builder->stack, node);
+ }
+ else {
+ Jim_Obj *objPtr = NULL;
+
+
+
+
+ if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
+ Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
+ return JIM_ERR;
+ }
+
+
+ if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
+ char *endptr;
+ if (t->type == JIM_TT_EXPR_INT) {
+ objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
+ }
+ else {
+ objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
+ }
+ if (endptr != t->token + t->len) {
+
+ Jim_FreeNewObj(interp, objPtr);
+ objPtr = NULL;
+ }
+ }
+
+ if (!objPtr) {
+
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ if (t->type == JIM_TT_CMD) {
+
+ Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
+ }
+ }
+
+
+ node = builder->next++;
+ node->objPtr = objPtr;
+ Jim_IncrRefCount(node->objPtr);
+ node->type = t->type;
+ Jim_StackPush(&builder->stack, node);
+ }
+ }
+
+ if (builder->stack.len == exp_stacklen) {
+ builder->level--;
+ return JIM_OK;
+ }
+
+ if ((flags & EXPR_FUNC_ARGS)) {
+ Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
+ }
+ else {
+ if (builder->stack.len < exp_stacklen) {
+ if (builder->level == 0) {
+ Jim_SetResultFormatted(interp, "empty expression");
+ }
+ else {
+ Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
+ }
+ }
+ else {
+ Jim_SetResultFormatted(interp, "extra terms after expression");
+ }
+ }
+
+ return JIM_ERR;
+}
+
+static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
+{
+ struct ExprTree *expr;
+ struct ExprBuilder builder;
+ int rc;
+ struct JimExprNode *top = NULL;
+
+ builder.parencount = 0;
+ builder.level = 0;
+ builder.token = builder.first_token = tokenlist->list;
+ builder.exprObjPtr = exprObjPtr;
+ builder.fileNameObj = fileNameObj;
+
+ builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
+ memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
+ builder.next = builder.nodes;
+ Jim_InitStack(&builder.stack);
+
+ rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
+
+ if (rc == JIM_OK) {
+ top = Jim_StackPop(&builder.stack);
+
+ if (builder.parencount) {
+ Jim_SetResultString(interp, "missing close parenthesis", -1);
+ rc = JIM_ERR;
+ }
+ }
+
+
+ Jim_FreeStack(&builder.stack);
+
+ if (rc != JIM_OK) {
+ ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
+ return NULL;
+ }
+
+ expr = Jim_Alloc(sizeof(*expr));
+ expr->inUse = 1;
+ expr->expr = top;
+ expr->nodes = builder.nodes;
+ expr->len = builder.next - builder.nodes;
+
+ assert(expr->len <= tokenlist->count - 1);
+
+ return expr;
+}
+
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int exprTextLen;
+ const char *exprText;
+ struct JimParserCtx parser;
+ struct ExprTree *expr;
+ ParseTokenList tokenlist;
+ int line;
+ Jim_Obj *fileNameObj;
+ int rc = JIM_ERR;
+
+
+ fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
+ Jim_IncrRefCount(fileNameObj);
+
+ exprText = Jim_GetString(objPtr, &exprTextLen);
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, exprText, exprTextLen, line);
+ while (!parser.eof) {
+ if (JimParseExpression(&parser) != JIM_OK) {
+ ScriptTokenListFree(&tokenlist);
+ Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+ if (parser.errmsg) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
+ }
+ expr = NULL;
+ goto err;
+ }
+
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+#ifdef DEBUG_SHOW_EXPR_TOKENS
+ {
+ int i;
+ printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
+ for (i = 0; i < tokenlist.count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
+ tokenlist.list[i].len, tokenlist.list[i].token);
+ }
+ }
+#endif
+
+ if (tokenlist.count <= 1) {
+ Jim_SetResultString(interp, "empty expression", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ rc = JimParseCheckMissing(interp, parser.missing.ch);
+ }
+ if (rc != JIM_OK) {
+ ScriptTokenListFree(&tokenlist);
+ Jim_DecrRefCount(interp, fileNameObj);
+ return rc;
+ }
+
+
+ expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+ if (!expr) {
+ goto err;
+ }
+
+#ifdef DEBUG_SHOW_EXPR
+ printf("==== Expr ====\n");
+ JimShowExprNode(expr->expr, 0);
+#endif
+
+ rc = JIM_OK;
+
+ err:
+
+ Jim_DecrRefCount(interp, fileNameObj);
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, expr);
+ objPtr->typePtr = &exprObjType;
+ return rc;
+}
+
+static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &exprObjType) {
+ if (SetExprFromAny(interp, objPtr) != JIM_OK) {
+ return NULL;
+ }
+ }
+ return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
+}
+
+#ifdef JIM_OPTIMIZATION
+static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (node->type == JIM_TT_EXPR_INT)
+ return node->objPtr;
+ else if (node->type == JIM_TT_VAR)
+ return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
+ else if (node->type == JIM_TT_DICTSUGAR)
+ return JimExpandDictSugar(interp, node->objPtr);
+ else
+ return NULL;
+}
+#endif
+
+
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (TOKEN_IS_EXPR_OP(node->type)) {
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
+ return op->funcop(interp, node);
+ }
+ else {
+ Jim_Obj *objPtr;
+
+
+ switch (node->type) {
+ case JIM_TT_EXPR_INT:
+ case JIM_TT_EXPR_DOUBLE:
+ case JIM_TT_EXPR_BOOLEAN:
+ case JIM_TT_STR:
+ Jim_SetResult(interp, node->objPtr);
+ return JIM_OK;
+
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, node->objPtr);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_ESC:
+ if (interp->safeexpr) {
+ return JIM_ERR;
+ }
+ if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+
+ case JIM_TT_CMD:
+ if (interp->safeexpr) {
+ return JIM_ERR;
+ }
+ return Jim_EvalObj(interp, node->objPtr);
+
+ default:
+
+ return JIM_ERR;
+ }
+ }
+}
+
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
+{
+ int rc = JimExprEvalTermNode(interp, node);
+ if (rc == JIM_OK) {
+ *objPtrPtr = Jim_GetResult(interp);
+ Jim_IncrRefCount(*objPtrPtr);
+ }
+ return rc;
+}
+
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
+{
+ if (JimExprEvalTermNode(interp, node) == JIM_OK) {
+ return ExprBool(interp, Jim_GetResult(interp));
+ }
+ return -1;
+}
+
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
+{
+ struct ExprTree *expr;
+ int retcode = JIM_OK;
+
+ Jim_IncrRefCount(exprObjPtr);
+ expr = JimGetExpression(interp, exprObjPtr);
+ if (!expr) {
+ retcode = JIM_ERR;
+ goto done;
+ }
+
+#ifdef JIM_OPTIMIZATION
+ if (!interp->safeexpr) {
+ Jim_Obj *objPtr;
+
+
+ switch (expr->len) {
+ case 1:
+ objPtr = JimExprIntValOrVar(interp, expr->expr);
+ if (objPtr) {
+ Jim_SetResult(interp, objPtr);
+ goto done;
+ }
+ break;
+
+ case 2:
+ if (expr->expr->type == JIM_EXPROP_NOT) {
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
+
+ if (objPtr && JimIsWide(objPtr)) {
+ Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
+ goto done;
+ }
+ }
+ break;
+
+ case 3:
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
+ if (objPtr && JimIsWide(objPtr)) {
+ Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
+ if (objPtr2 && JimIsWide(objPtr2)) {
+ jim_wide wideValueA = JimWideValue(objPtr);
+ jim_wide wideValueB = JimWideValue(objPtr2);
+ int cmpRes;
+ switch (expr->expr->type) {
+ case JIM_EXPROP_LT:
+ cmpRes = wideValueA < wideValueB;
+ break;
+ case JIM_EXPROP_LTE:
+ cmpRes = wideValueA <= wideValueB;
+ break;
+ case JIM_EXPROP_GT:
+ cmpRes = wideValueA > wideValueB;
+ break;
+ case JIM_EXPROP_GTE:
+ cmpRes = wideValueA >= wideValueB;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ cmpRes = wideValueA == wideValueB;
+ break;
+ case JIM_EXPROP_NUMNE:
+ cmpRes = wideValueA != wideValueB;
+ break;
+ default:
+ goto noopt;
+ }
+ Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
+ goto done;
+ }
+ }
+ break;
+ }
+ }
+noopt:
+#endif
+
+ expr->inUse++;
+
+
+ retcode = JimExprEvalTermNode(interp, expr->expr);
+
+
+ Jim_FreeIntRep(interp, exprObjPtr);
+ exprObjPtr->typePtr = &exprObjType;
+ Jim_SetIntRepPtr(exprObjPtr, expr);
+
+done:
+ Jim_DecrRefCount(interp, exprObjPtr);
+
+ return retcode;
+}
+
+int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
+{
+ int retcode = Jim_EvalExpression(interp, exprObjPtr);
+
+ if (retcode == JIM_OK) {
+ switch (ExprBool(interp, Jim_GetResult(interp))) {
+ case 0:
+ *boolPtr = 0;
+ break;
+
+ case 1:
+ *boolPtr = 1;
+ break;
+
+ case -1:
+ retcode = JIM_ERR;
+ break;
+ }
+ }
+ return retcode;
+}
+
+
+
+
+typedef struct ScanFmtPartDescr
+{
+ const char *arg;
+ const char *prefix;
+ size_t width;
+ int pos;
+ char type;
+ char modifier;
+} ScanFmtPartDescr;
+
+
+typedef struct ScanFmtStringObj
+{
+ jim_wide size;
+ char *stringRep;
+ size_t count;
+ size_t convCount;
+ size_t maxPos;
+ const char *error;
+ char *scratch;
+ ScanFmtPartDescr descr[1];
+} ScanFmtStringObj;
+
+
+static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
+
+static const Jim_ObjType scanFmtStringObjType = {
+ "scanformatstring",
+ FreeScanFmtInternalRep,
+ DupScanFmtInternalRep,
+ UpdateStringOfScanFmt,
+ JIM_TYPE_NONE,
+};
+
+void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JIM_NOTUSED(interp);
+ Jim_Free((char *)objPtr->internalRep.ptr);
+ objPtr->internalRep.ptr = 0;
+}
+
+void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
+ ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
+
+ JIM_NOTUSED(interp);
+ memcpy(newVec, srcPtr->internalRep.ptr, size);
+ dupPtr->internalRep.ptr = newVec;
+ dupPtr->typePtr = &scanFmtStringObjType;
+}
+
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
+{
+ JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
+}
+
+
+static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ ScanFmtStringObj *fmtObj;
+ char *buffer;
+ int maxCount, i, approxSize, lastPos = -1;
+ const char *fmt = Jim_String(objPtr);
+ int maxFmtLen = Jim_Length(objPtr);
+ const char *fmtEnd = fmt + maxFmtLen;
+ int curr;
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
+ if (fmt[i] == '%')
+ ++maxCount;
+
+ approxSize = sizeof(ScanFmtStringObj)
+ +(maxCount + 1) * sizeof(ScanFmtPartDescr)
+ +maxFmtLen * sizeof(char) + 3 + 1
+ + maxFmtLen * sizeof(char) + 1
+ + maxFmtLen * sizeof(char)
+ +(maxCount + 1) * sizeof(char)
+ +1;
+ fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
+ memset(fmtObj, 0, approxSize);
+ fmtObj->size = approxSize;
+ fmtObj->maxPos = 0;
+ fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
+ fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
+ memcpy(fmtObj->stringRep, fmt, maxFmtLen);
+ buffer = fmtObj->stringRep + maxFmtLen + 1;
+ objPtr->internalRep.ptr = fmtObj;
+ objPtr->typePtr = &scanFmtStringObjType;
+ for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
+ int width = 0, skip;
+ ScanFmtPartDescr *descr = &fmtObj->descr[curr];
+
+ fmtObj->count++;
+ descr->width = 0;
+
+ if (*fmt != '%' || fmt[1] == '%') {
+ descr->type = 0;
+ descr->prefix = &buffer[i];
+ for (; fmt < fmtEnd; ++fmt) {
+ if (*fmt == '%') {
+ if (fmt[1] != '%')
+ break;
+ ++fmt;
+ }
+ buffer[i++] = *fmt;
+ }
+ buffer[i++] = 0;
+ }
+
+ ++fmt;
+
+ if (fmt >= fmtEnd)
+ goto done;
+ descr->pos = 0;
+ if (*fmt == '*') {
+ descr->pos = -1;
+ ++fmt;
+ }
+ else
+ fmtObj->convCount++;
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ fmt += skip;
+
+ if (descr->pos != -1 && *fmt == '$') {
+ int prev;
+
+ ++fmt;
+ descr->pos = width;
+ width = 0;
+
+ if ((lastPos == 0 && descr->pos > 0)
+ || (lastPos > 0 && descr->pos == 0)) {
+ fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+
+ for (prev = 0; prev < curr; ++prev) {
+ if (fmtObj->descr[prev].pos == -1)
+ continue;
+ if (fmtObj->descr[prev].pos == descr->pos) {
+ fmtObj->error =
+ "variable is assigned by multiple \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+ }
+ if (descr->pos < 0) {
+ fmtObj->error =
+ "\"%n$\" conversion specifier is negative";
+ return JIM_ERR;
+ }
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ descr->width = width;
+ fmt += skip;
+ }
+ if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
+ fmtObj->maxPos = descr->pos;
+ }
+ else {
+
+ descr->width = width;
+ }
+ }
+
+ if (lastPos == -1)
+ lastPos = descr->pos;
+
+ if (*fmt == '[') {
+ int swapped = 1, beg = i, end, j;
+
+ descr->type = '[';
+ descr->arg = &buffer[i];
+ ++fmt;
+ if (*fmt == '^')
+ buffer[i++] = *fmt++;
+ if (*fmt == ']')
+ buffer[i++] = *fmt++;
+ while (*fmt && *fmt != ']')
+ buffer[i++] = *fmt++;
+ if (*fmt != ']') {
+ fmtObj->error = "unmatched [ in format string";
+ return JIM_ERR;
+ }
+ end = i;
+ buffer[i++] = 0;
+
+ while (swapped) {
+ swapped = 0;
+ for (j = beg + 1; j < end - 1; ++j) {
+ if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
+ char tmp = buffer[j - 1];
+
+ buffer[j - 1] = buffer[j + 1];
+ buffer[j + 1] = tmp;
+ swapped = 1;
+ }
+ }
+ }
+ }
+ else {
+
+ if (fmt < fmtEnd && strchr("hlL", *fmt))
+ descr->modifier = tolower((int)*fmt++);
+
+ if (fmt >= fmtEnd) {
+ fmtObj->error = "missing scan conversion character";
+ return JIM_ERR;
+ }
+
+ descr->type = *fmt;
+ if (strchr("efgcsndoxui", *fmt) == 0) {
+ fmtObj->error = "bad scan conversion character";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'c' && descr->width != 0) {
+ fmtObj->error = "field width may not be specified in %c " "conversion";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'u' && descr->modifier == 'l') {
+ fmtObj->error = "unsigned wide not supported";
+ return JIM_ERR;
+ }
+ }
+ curr++;
+ }
+ done:
+ return JIM_OK;
+}
+
+
+
+#define FormatGetCnvCount(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
+#define FormatGetMaxPos(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
+#define FormatGetError(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
+
+static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
+{
+ char *buffer = Jim_StrDup(str);
+ char *p = buffer;
+
+ while (*str) {
+ int c;
+ int n;
+
+ if (!sdescr && isspace(UCHAR(*str)))
+ break;
+
+ n = utf8_tounicode(str, &c);
+ if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
+ break;
+ while (n--)
+ *p++ = *str++;
+ }
+ *p = 0;
+ return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
+}
+
+
+static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
+ ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
+{
+ const char *tok;
+ const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
+ size_t scanned = 0;
+ size_t anchor = pos;
+ int i;
+ Jim_Obj *tmpObj = NULL;
+
+
+ *valObjPtr = 0;
+ if (descr->prefix) {
+ for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {
+
+ if (isspace(UCHAR(descr->prefix[i])))
+ while (pos < str_bytelen && isspace(UCHAR(str[pos])))
+ ++pos;
+ else if (descr->prefix[i] != str[pos])
+ break;
+ else
+ ++pos;
+ }
+ if (pos >= str_bytelen) {
+ return -1;
+ }
+ else if (descr->prefix[i] != 0)
+ return 0;
+ }
+
+ if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
+ while (isspace(UCHAR(str[pos])))
+ ++pos;
+
+
+ scanned = pos - anchor;
+
+
+ if (descr->type == 'n') {
+
+ *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
+ }
+ else if (pos >= str_bytelen) {
+
+ return -1;
+ }
+ else if (descr->type == 'c') {
+ int c;
+ scanned += utf8_tounicode(&str[pos], &c);
+ *valObjPtr = Jim_NewIntObj(interp, c);
+ return scanned;
+ }
+ else {
+
+ if (descr->width > 0) {
+ size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
+ size_t tLen = descr->width > sLen ? sLen : descr->width;
+
+ tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
+ tok = tmpObj->bytes;
+ }
+ else {
+
+ tok = &str[pos];
+ }
+ switch (descr->type) {
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'u':
+ case 'i':{
+ char *endp;
+ jim_wide w;
+
+ int base = descr->type == 'o' ? 8
+ : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
+
+
+ if (base == 0) {
+ w = jim_strtoull(tok, &endp);
+ }
+ else {
+ w = strtoull(tok, &endp, base);
+ }
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewIntObj(interp, w);
+
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ case 's':
+ case '[':{
+ *valObjPtr = JimScanAString(interp, descr->arg, tok);
+ scanned += Jim_Length(*valObjPtr);
+ break;
+ }
+ case 'e':
+ case 'f':
+ case 'g':{
+ char *endp;
+ double value = strtod(tok, &endp);
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewDoubleObj(interp, value);
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ }
+ if (tmpObj) {
+ Jim_FreeNewObj(interp, tmpObj);
+ }
+ }
+ return scanned;
+}
+
+
+Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
+{
+ size_t i, pos;
+ int scanned = 1;
+ const char *str = Jim_String(strObjPtr);
+ int str_bytelen = Jim_Length(strObjPtr);
+ Jim_Obj *resultList = 0;
+ Jim_Obj **resultVec = 0;
+ int resultc;
+ Jim_Obj *emptyStr = 0;
+ ScanFmtStringObj *fmtObj;
+
+
+ JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
+
+ fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
+
+ if (fmtObj->error != 0) {
+ if (flags & JIM_ERRMSG)
+ Jim_SetResultString(interp, fmtObj->error, -1);
+ return 0;
+ }
+
+ emptyStr = Jim_NewEmptyStringObj(interp);
+ Jim_IncrRefCount(emptyStr);
+
+ resultList = Jim_NewListObj(interp, NULL, 0);
+ if (fmtObj->maxPos > 0) {
+ for (i = 0; i < fmtObj->maxPos; ++i)
+ Jim_ListAppendElement(interp, resultList, emptyStr);
+ JimListGetElements(interp, resultList, &resultc, &resultVec);
+ }
+
+ for (i = 0, pos = 0; i < fmtObj->count; ++i) {
+ ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
+ Jim_Obj *value = 0;
+
+
+ if (descr->type == 0)
+ continue;
+
+ if (scanned > 0)
+ scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);
+
+ if (scanned == -1 && i == 0)
+ goto eof;
+
+ pos += scanned;
+
+
+ if (value == 0)
+ value = Jim_NewEmptyStringObj(interp);
+
+ if (descr->pos == -1) {
+ Jim_FreeNewObj(interp, value);
+ }
+ else if (descr->pos == 0)
+
+ Jim_ListAppendElement(interp, resultList, value);
+ else if (resultVec[descr->pos - 1] == emptyStr) {
+
+ Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
+ Jim_IncrRefCount(value);
+ resultVec[descr->pos - 1] = value;
+ }
+ else {
+
+ Jim_FreeNewObj(interp, value);
+ goto err;
+ }
+ }
+ Jim_DecrRefCount(interp, emptyStr);
+ return resultList;
+ eof:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return (Jim_Obj *)EOF;
+ err:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return 0;
+}
+
+
+static void JimPrngInit(Jim_Interp *interp)
+{
+#define PRNG_SEED_SIZE 256
+ int i;
+ unsigned int *seed;
+ time_t t = time(NULL);
+
+ interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
+
+ seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
+ for (i = 0; i < PRNG_SEED_SIZE; i++) {
+ seed[i] = (rand() ^ t ^ clock());
+ }
+ JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
+ Jim_Free(seed);
+}
+
+
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
+{
+ Jim_PrngState *prng;
+ unsigned char *destByte = (unsigned char *)dest;
+ unsigned int si, sj, x;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+ for (x = 0; x < len; x++) {
+ prng->i = (prng->i + 1) & 0xff;
+ si = prng->sbox[prng->i];
+ prng->j = (prng->j + si) & 0xff;
+ sj = prng->sbox[prng->j];
+ prng->sbox[prng->i] = sj;
+ prng->sbox[prng->j] = si;
+ *destByte++ = prng->sbox[(si + sj) & 0xff];
+ }
+}
+
+
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
+{
+ int i;
+ Jim_PrngState *prng;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+
+ for (i = 0; i < 256; i++)
+ prng->sbox[i] = i;
+
+ for (i = 0; i < seedLen; i++) {
+ unsigned char t;
+
+ t = prng->sbox[i & 0xFF];
+ prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
+ prng->sbox[seed[i]] = t;
+ }
+ prng->i = prng->j = 0;
+
+ for (i = 0; i < 256; i += seedLen) {
+ JimRandomBytes(interp, seed, seedLen);
+ }
+}
+
+
+static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide wideValue, increment = 1;
+ Jim_Obj *intObjPtr;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
+ return JIM_ERR;
+ }
+ intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!intObjPtr) {
+
+ wideValue = 0;
+ }
+ else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (!intObjPtr || Jim_IsShared(intObjPtr)) {
+ intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
+ if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, intObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+
+ Jim_InvalidateStringRep(intObjPtr);
+ JimWideValue(intObjPtr) = wideValue + increment;
+
+ if (argv[1]->typePtr != &variableObjType) {
+
+ Jim_SetVariable(interp, argv[1], intObjPtr);
+ }
+ }
+ Jim_SetResult(interp, intObjPtr);
+ return JIM_OK;
+}
+
+
+#define JIM_EVAL_SARGV_LEN 8
+#define JIM_EVAL_SINTV_LEN 8
+
+static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
+{
+ JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
+
+ int ret;
+ Jim_Obj *nargv[7];
+ Jim_Obj *traceCmdObj = interp->traceCmdObj;
+ Jim_Obj *resultObj = Jim_GetResult(interp);
+ ScriptObj *script = NULL;
+
+
+
+ if (interp->evalFrame->scriptObj) {
+ script = JimGetScript(interp, interp->evalFrame->scriptObj);
+ }
+
+ nargv[0] = traceCmdObj;
+ nargv[1] = Jim_NewStringObj(interp, type, -1);
+ nargv[2] = script ? script->fileNameObj : interp->emptyObj;
+ nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
+ nargv[4] = resultObj;
+ nargv[5] = argv[0];
+ nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
+
+
+ interp->traceCmdObj = NULL;
+
+ Jim_IncrRefCount(resultObj);
+ ret = Jim_EvalObjVector(interp, 7, nargv);
+ Jim_DecrRefCount(interp, resultObj);
+
+ if (ret == JIM_OK || ret == JIM_RETURN) {
+
+ interp->traceCmdObj = traceCmdObj;
+ Jim_SetEmptyResult(interp);
+ ret = JIM_OK;
+ }
+ else {
+
+ Jim_DecrRefCount(interp, traceCmdObj);
+ }
+ return ret;
+}
+
+
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (interp->unknown_called > 50) {
+ return JIM_ERR;
+ }
+
+
+
+ if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
+ return JIM_ERR;
+
+ interp->unknown_called++;
+
+ retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
+ interp->unknown_called--;
+
+ return retcode;
+}
+
+static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
+{
+ memset(frame, 0, sizeof(*frame));
+ frame->parent = interp->evalFrame;
+ frame->level = frame->parent->level + 1;
+ frame->procLevel = interp->procLevel;
+ frame->framePtr = interp->framePtr;
+ if (scriptObj) {
+ frame->scriptObj = scriptObj;
+ }
+ else {
+ frame->scriptObj = frame->parent->scriptObj;
+ }
+ interp->evalFrame = frame;
+#if 0
+ if (frame->scriptObj) {
+ printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
+ }
+#endif
+}
+
+static void JimPopEvalFrame(Jim_Interp *interp)
+{
+ interp->evalFrame = interp->evalFrame->parent;
+}
+
+
+static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int retcode;
+ Jim_Cmd *cmdPtr;
+ void *prevPrivData;
+ Jim_Obj *tailcallObj = NULL;
+
+#if 0
+ printf("invoke");
+ int j;
+ for (j = 0; j < objc; j++) {
+ printf(" '%s'", Jim_String(objv[j]));
+ }
+ printf("\n");
+#endif
+
+ cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+ if (cmdPtr == NULL) {
+ return JimUnknown(interp, objc, objv);
+ }
+ JimIncrCmdRefCount(cmdPtr);
+
+ if (interp->evalDepth == interp->maxEvalDepth) {
+ Jim_SetResultString(interp, "Infinite eval recursion", -1);
+ retcode = JIM_ERR;
+ goto out;
+ }
+ interp->evalDepth++;
+ prevPrivData = interp->cmdPrivData;
+
+tailcall:
+
+ interp->evalFrame->argc = objc;
+ interp->evalFrame->argv = objv;
+ interp->evalFrame->cmd = cmdPtr;
+
+ if (!interp->traceCmdObj ||
+ (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
+
+ Jim_SetEmptyResult(interp);
+ if (cmdPtr->isproc) {
+ retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+ }
+ else {
+ interp->cmdPrivData = cmdPtr->u.native.privData;
+ retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+ }
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+ }
+
+ if (tailcallObj) {
+
+ Jim_DecrRefCount(interp, tailcallObj);
+ tailcallObj = NULL;
+ }
+
+
+ interp->evalFrame->argc = 0;
+ interp->evalFrame->argv = NULL;
+
+
+ if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+
+ cmdPtr = interp->framePtr->tailcallCmd;
+ interp->framePtr->tailcallCmd = NULL;
+ tailcallObj = interp->framePtr->tailcallObj;
+ interp->framePtr->tailcallObj = NULL;
+ objc = tailcallObj->internalRep.listValue.len;
+ objv = tailcallObj->internalRep.listValue.ele;
+ goto tailcall;
+ }
+
+ interp->cmdPrivData = prevPrivData;
+ interp->evalDepth--;
+
+out:
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+
+ if (interp->framePtr->tailcallObj) {
+ JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
+ Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
+ interp->framePtr->tailcallCmd = NULL;
+ interp->framePtr->tailcallObj = NULL;
+ }
+
+ return retcode;
+}
+
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i, retcode;
+ Jim_EvalFrame frame;
+
+
+ for (i = 0; i < objc; i++)
+ Jim_IncrRefCount(objv[i]);
+
+
+ JimPushEvalFrame(interp, &frame, NULL);
+
+ retcode = JimInvokeCommand(interp, objc, objv);
+
+ JimPopEvalFrame(interp);
+
+
+ for (i = 0; i < objc; i++)
+ Jim_DecrRefCount(interp, objv[i]);
+
+ return retcode;
+}
+
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
+{
+ int ret;
+ Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
+
+ nargv[0] = prefix;
+ memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
+ ret = Jim_EvalObjVector(interp, objc + 1, nargv);
+ Jim_Free(nargv);
+ return ret;
+}
+
+static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
+{
+ Jim_Obj *objPtr;
+ int ret = JIM_ERR;
+
+ switch (token->type) {
+ case JIM_TT_STR:
+ case JIM_TT_ESC:
+ objPtr = token->objPtr;
+ break;
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, token->objPtr);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ ret = Jim_EvalExpression(interp, token->objPtr);
+ if (ret == JIM_OK) {
+ objPtr = Jim_GetResult(interp);
+ }
+ else {
+ objPtr = NULL;
+ }
+ break;
+ case JIM_TT_CMD:
+ ret = Jim_EvalObj(interp, token->objPtr);
+ if (ret == JIM_OK || ret == JIM_RETURN) {
+ objPtr = interp->result;
+ } else {
+
+ objPtr = NULL;
+ }
+ break;
+ default:
+ JimPanic((1,
+ "default token type (%d) reached " "in Jim_SubstObj().", token->type));
+ objPtr = NULL;
+ break;
+ }
+ if (objPtr) {
+ *objPtrPtr = objPtr;
+ return JIM_OK;
+ }
+ return ret;
+}
+
+static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
+{
+ int totlen = 0, i;
+ Jim_Obj **intv;
+ Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
+ Jim_Obj *objPtr;
+ char *s;
+
+ if (tokens <= JIM_EVAL_SINTV_LEN)
+ intv = sintv;
+ else
+ intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
+
+ for (i = 0; i < tokens; i++) {
+ switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
+ case JIM_OK:
+ case JIM_RETURN:
+ break;
+ case JIM_BREAK:
+ if (flags & JIM_SUBST_FLAG) {
+
+ tokens = i;
+ continue;
+ }
+
+
+ case JIM_CONTINUE:
+ if (flags & JIM_SUBST_FLAG) {
+ intv[i] = NULL;
+ continue;
+ }
+
+
+ default:
+ while (i--) {
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+ return NULL;
+ }
+ Jim_IncrRefCount(intv[i]);
+ Jim_String(intv[i]);
+ totlen += intv[i]->length;
+ }
+
+
+ if (tokens == 1 && intv[0] && intv == sintv) {
+
+ intv[0]->refCount--;
+ return intv[0];
+ }
+
+ objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
+
+ if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
+ && token[2].type == JIM_TT_VAR) {
+
+ objPtr->typePtr = &interpolatedObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
+ Jim_IncrRefCount(intv[2]);
+ }
+ else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
+
+ int line;
+ Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
+ Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
+ }
+
+
+ s = objPtr->bytes = Jim_Alloc(totlen + 1);
+ objPtr->length = totlen;
+ for (i = 0; i < tokens; i++) {
+ if (intv[i]) {
+ memcpy(s, intv[i]->bytes, intv[i]->length);
+ s += intv[i]->length;
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ }
+ objPtr->bytes[totlen] = '\0';
+
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+
+ return objPtr;
+}
+
+
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ int retcode = JIM_OK;
+ Jim_EvalFrame frame;
+
+ JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
+
+ JimPushEvalFrame(interp, &frame, NULL);
+
+ if (listPtr->internalRep.listValue.len) {
+ Jim_IncrRefCount(listPtr);
+ retcode = JimInvokeCommand(interp,
+ listPtr->internalRep.listValue.len,
+ listPtr->internalRep.listValue.ele);
+ Jim_DecrRefCount(interp, listPtr);
+ }
+
+ JimPopEvalFrame(interp);
+
+ return retcode;
+}
+
+int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ SetListFromAny(interp, listPtr);
+ return JimEvalObjList(interp, listPtr);
+}
+
+int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+ int i;
+ ScriptObj *script;
+ ScriptToken *token;
+ int retcode = JIM_OK;
+ Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
+ Jim_EvalFrame frame;
+
+ if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+ return JimEvalObjList(interp, scriptObjPtr);
+ }
+
+ Jim_IncrRefCount(scriptObjPtr);
+ script = JimGetScript(interp, scriptObjPtr);
+ if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
+ JimSetErrorStack(interp, script);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_ERR;
+ }
+
+ Jim_SetEmptyResult(interp);
+
+ token = script->token;
+
+#ifdef JIM_OPTIMIZATION
+ if (script->len == 0) {
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_OK;
+ }
+ if (script->len == 3
+ && token[1].objPtr->typePtr == &commandObjType
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
+ && token[2].objPtr->typePtr == &variableObjType) {
+
+ Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ JimWideValue(objPtr)++;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+#endif
+
+ script->inUse++;
+
+ JimPushEvalFrame(interp, &frame, scriptObjPtr);
+
+
+ interp->errorFlag = 0;
+ argv = sargv;
+
+ for (i = 0; i < script->len && retcode == JIM_OK; ) {
+ int argc;
+ int j;
+
+
+ argc = token[i].objPtr->internalRep.scriptLineValue.argc;
+ script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
+
+
+ if (argc > JIM_EVAL_SARGV_LEN)
+ argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
+
+
+ i++;
+
+ for (j = 0; j < argc; j++) {
+ long wordtokens = 1;
+ int expand = 0;
+ Jim_Obj *wordObjPtr = NULL;
+
+ if (token[i].type == JIM_TT_WORD) {
+ wordtokens = JimWideValue(token[i++].objPtr);
+ if (wordtokens < 0) {
+ expand = 1;
+ wordtokens = -wordtokens;
+ }
+ }
+
+ if (wordtokens == 1) {
+
+ switch (token[i].type) {
+ case JIM_TT_ESC:
+ case JIM_TT_STR:
+ wordObjPtr = token[i].objPtr;
+ break;
+ case JIM_TT_VAR:
+ wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ retcode = Jim_EvalExpression(interp, token[i].objPtr);
+ if (retcode == JIM_OK) {
+ wordObjPtr = Jim_GetResult(interp);
+ }
+ else {
+ wordObjPtr = NULL;
+ }
+ break;
+ case JIM_TT_DICTSUGAR:
+ wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
+ break;
+ case JIM_TT_CMD:
+ retcode = Jim_EvalObj(interp, token[i].objPtr);
+ if (retcode == JIM_OK) {
+ wordObjPtr = Jim_GetResult(interp);
+ }
+ break;
+ default:
+ JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
+ }
+ }
+ else {
+ wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
+ }
+
+ if (!wordObjPtr) {
+ if (retcode == JIM_OK) {
+ retcode = JIM_ERR;
+ }
+ break;
+ }
+
+ Jim_IncrRefCount(wordObjPtr);
+ i += wordtokens;
+
+ if (!expand) {
+ argv[j] = wordObjPtr;
+ }
+ else {
+
+ int len = Jim_ListLength(interp, wordObjPtr);
+ int newargc = argc + len - 1;
+ int k;
+
+ if (len > 1) {
+ if (argv == sargv) {
+ if (newargc > JIM_EVAL_SARGV_LEN) {
+ argv = Jim_Alloc(sizeof(*argv) * newargc);
+ memcpy(argv, sargv, sizeof(*argv) * j);
+ }
+ }
+ else {
+
+ argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
+ }
+ }
+
+
+ for (k = 0; k < len; k++) {
+ argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
+ Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
+ }
+
+ Jim_DecrRefCount(interp, wordObjPtr);
+
+
+ j--;
+ argc += len - 1;
+ }
+ }
+
+ if (retcode == JIM_OK && argc) {
+
+ retcode = JimInvokeCommand(interp, argc, argv);
+
+ if (Jim_CheckSignal(interp)) {
+ retcode = JIM_SIGNAL;
+ }
+ }
+
+
+ while (j-- > 0) {
+ Jim_DecrRefCount(interp, argv[j]);
+ }
+
+ if (argv != sargv) {
+ Jim_Free(argv);
+ argv = sargv;
+ }
+ }
+
+
+ if (retcode == JIM_ERR) {
+ JimSetErrorStack(interp, NULL);
+ }
+
+ JimPopEvalFrame(interp);
+
+ Jim_FreeIntRep(interp, scriptObjPtr);
+ scriptObjPtr->typePtr = &scriptObjType;
+ Jim_SetIntRepPtr(scriptObjPtr, script);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ return retcode;
+}
+
+static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
+{
+ int retcode;
+
+ const char *varname = Jim_String(argNameObj);
+ if (*varname == '&') {
+
+ Jim_Obj *objPtr;
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = interp->framePtr->parent;
+ objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
+ interp->framePtr = savedCallFrame;
+ if (!objPtr) {
+ return JIM_ERR;
+ }
+
+
+ objPtr = Jim_NewStringObj(interp, varname + 1, -1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ retcode = Jim_SetVariable(interp, argNameObj, argValObj);
+ }
+ return retcode;
+}
+
+static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
+{
+
+ Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
+ int i;
+
+ for (i = 0; i < cmd->u.proc.argListLen; i++) {
+ Jim_AppendString(interp, argmsg, " ", 1);
+
+ if (i == cmd->u.proc.argsPos) {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
+ Jim_AppendString(interp, argmsg, " ...?", -1);
+ }
+ else {
+
+ Jim_AppendString(interp, argmsg, "?arg ...?", -1);
+ }
+ }
+ else {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+ Jim_AppendString(interp, argmsg, "?", 1);
+ }
+ else {
+ const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
+ if (*arg == '&') {
+ arg++;
+ }
+ Jim_AppendString(interp, argmsg, arg, -1);
+ }
+ }
+ }
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
+}
+
+#ifdef jim_ext_namespace
+int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *callFramePtr;
+ int retcode;
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
+ callFramePtr->argv = interp->evalFrame->argv;
+ callFramePtr->argc = interp->evalFrame->argc;
+ callFramePtr->procArgsObjPtr = NULL;
+ callFramePtr->procBodyObjPtr = scriptObj;
+ callFramePtr->staticVars = NULL;
+ Jim_IncrRefCount(scriptObj);
+ interp->framePtr = callFramePtr;
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ retcode = JIM_ERR;
+ }
+ else {
+
+ retcode = Jim_EvalObj(interp, scriptObj);
+ }
+
+
+ interp->framePtr = interp->framePtr->parent;
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
+
+ return retcode;
+}
+#endif
+
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
+{
+ Jim_CallFrame *callFramePtr;
+ int i, d, retcode, optargs;
+
+
+ if (argc - 1 < cmd->u.proc.reqArity ||
+ (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
+ JimSetProcWrongArgs(interp, argv[0], cmd);
+ return JIM_ERR;
+ }
+
+ if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
+
+ return JIM_OK;
+ }
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ return JIM_ERR;
+ }
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
+ callFramePtr->argv = argv;
+ callFramePtr->argc = argc;
+ callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
+ callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
+ callFramePtr->staticVars = cmd->u.proc.staticVars;
+
+ interp->procLevel++;
+
+ Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
+ Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
+ interp->framePtr = callFramePtr;
+
+
+ optargs = (argc - 1 - cmd->u.proc.reqArity);
+
+
+ i = 1;
+ for (d = 0; d < cmd->u.proc.argListLen; d++) {
+ Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
+ if (d == cmd->u.proc.argsPos) {
+
+ Jim_Obj *listObjPtr;
+ int argsLen = 0;
+ if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
+ argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
+ }
+ listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr) {
+ nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
+ }
+ retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+
+ i += argsLen;
+ continue;
+ }
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
+ retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
+ }
+ else {
+
+ retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
+ }
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+ }
+
+ if (interp->traceCmdObj == NULL ||
+ (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {
+
+ retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+ }
+
+badargset:
+
+
+ retcode = JimInvokeDefer(interp, retcode);
+ interp->framePtr = interp->framePtr->parent;
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
+
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+ interp->procLevel--;
+
+ return retcode;
+}
+
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
+{
+ int retval;
+ Jim_Obj *scriptObjPtr;
+
+ scriptObjPtr = Jim_NewStringObj(interp, script, -1);
+ Jim_IncrRefCount(scriptObjPtr);
+ if (filename) {
+ Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+ }
+ retval = Jim_EvalObj(interp, scriptObjPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return retval;
+}
+
+int Jim_Eval(Jim_Interp *interp, const char *script)
+{
+ return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
+}
+
+
+int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_Eval(interp, script);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_EvalFile(interp, filename);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+#include
+
+static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
+{
+ jim_stat_t sb;
+ int fd;
+ char *buf;
+ int readlen;
+
+ if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+ return NULL;
+ }
+ buf = Jim_Alloc(sb.st_size + 1);
+ readlen = read(fd, buf, sb.st_size);
+ close(fd);
+ if (readlen < 0) {
+ Jim_Free(buf);
+ Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+ return NULL;
+ }
+ else {
+ Jim_Obj *objPtr;
+ buf[readlen] = 0;
+
+ objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+
+ return objPtr;
+ }
+}
+
+
+int Jim_EvalFile(Jim_Interp *interp, const char *filename)
+{
+ Jim_Obj *filenameObj;
+ Jim_Obj *oldFilenameObj;
+ Jim_Obj *scriptObjPtr;
+ int retcode;
+
+ scriptObjPtr = JimReadTextFile(interp, filename);
+ if (!scriptObjPtr) {
+ return JIM_ERR;
+ }
+
+ filenameObj = Jim_NewStringObj(interp, filename, -1);
+ Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
+
+ oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
+
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+
+ JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
+
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+
+ return retcode;
+}
+
+static void JimParseSubst(struct JimParserCtx *pc, int flags)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+
+ if (pc->len == 0) {
+ pc->tend = pc->p;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ JimParseCmd(pc);
+ return;
+ }
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ if (JimParseVar(pc) == JIM_OK) {
+ return;
+ }
+
+ pc->tstart = pc->p;
+
+ pc->p++;
+ pc->len--;
+ }
+ while (pc->len) {
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ break;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ break;
+ }
+ if (*pc->p == '\\' && pc->len > 1) {
+ pc->p++;
+ pc->len--;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
+}
+
+
+static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script = Jim_Alloc(sizeof(*script));
+ ParseTokenList tokenlist;
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, 1);
+ while (1) {
+ JimParseSubst(&parser, flags);
+ if (parser.eof) {
+
+ break;
+ }
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+
+ script->inUse = 1;
+ script->substFlags = flags;
+ script->fileNameObj = interp->emptyObj;
+ Jim_IncrRefCount(script->fileNameObj);
+ SubstObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+#ifdef DEBUG_SHOW_SUBST
+ {
+ int i;
+
+ printf("==== Subst ====\n");
+ for (i = 0; i < script->len; i++) {
+ printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
+ Jim_String(script->token[i].objPtr));
+ }
+ }
+#endif
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+ return JIM_OK;
+}
+
+static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
+ SetSubstFromAny(interp, objPtr, flags);
+ return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
+{
+ ScriptObj *script;
+
+ JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
+
+ script = Jim_GetSubst(interp, substObjPtr, flags);
+
+ Jim_IncrRefCount(substObjPtr);
+ script->inUse++;
+
+ *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
+
+ script->inUse--;
+ Jim_DecrRefCount(interp, substObjPtr);
+ if (*resObjPtrPtr == NULL) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
+{
+ Jim_Obj *objPtr;
+ Jim_Obj *listObjPtr;
+
+ JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
+
+ listObjPtr = Jim_NewListObj(interp, argv, argc);
+
+ if (msg && *msg) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
+ }
+ Jim_IncrRefCount(listObjPtr);
+ objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
+ Jim_DecrRefCount(interp, listObjPtr);
+
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
+}
+
+typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);
+
+#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
+
+static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
+ JimHashtableIteratorCallbackType *callback, int type)
+{
+ Jim_HashEntry *he;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
+ he = Jim_FindHashEntry(ht, patternObjPtr);
+ if (he) {
+ callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+ patternObjPtr, type);
+ }
+ }
+ else {
+ Jim_HashTableIterator htiter;
+ JimInitHashTableIterator(ht, &htiter);
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
+ callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+ patternObjPtr, type);
+ }
+ }
+ return listObjPtr;
+}
+
+
+#define JIM_CMDLIST_COMMANDS 0
+#define JIM_CMDLIST_PROCS 1
+#define JIM_CMDLIST_CHANNELS 2
+
+static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
+{
+ Jim_Cmd *cmdPtr = (Jim_Cmd *)value;
+
+ if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
+
+ return;
+ }
+
+ Jim_IncrRefCount(keyObj);
+
+ if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
+ int match = 1;
+ if (patternObj) {
+ int plen, slen;
+ const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
+ const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
+#ifdef JIM_NO_INTROSPECTION
+
+ match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
+#else
+ match = JimGlobMatch(pattern, plen, str, slen, 0);
+#endif
+ }
+ if (match) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ }
+ }
+ Jim_DecrRefCount(interp, keyObj);
+}
+
+static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
+{
+ return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
+}
+
+
+#define JIM_VARLIST_GLOBALS 0
+#define JIM_VARLIST_LOCALS 1
+#define JIM_VARLIST_VARS 2
+#define JIM_VARLIST_MASK 0x000f
+
+#define JIM_VARLIST_VALUES 0x1000
+
+static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
+{
+ Jim_VarVal *vv = (Jim_VarVal *)value;
+
+ if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
+ if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ if (type & JIM_VARLIST_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
+ }
+ }
+ }
+}
+
+
+static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
+{
+ if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
+ return interp->emptyObj;
+ }
+ else {
+ Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
+ return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
+ mode);
+ }
+}
+
+static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
+{
+ long level;
+
+ if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+ Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
+ if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
+#ifdef JIM_NO_INTROSPECTION
+
+ *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
+#else
+ *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+#endif
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return JIM_ERR;
+}
+
+static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
+{
+ long level;
+
+ if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
+ if (frame) {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
+ if (frame->scriptObj) {
+ ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
+ Jim_ListAppendElement(interp, listObj, script->fileNameObj);
+ }
+#ifndef JIM_NO_INTROSPECTION
+ {
+ Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
+
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
+ Jim_ListAppendElement(interp, listObj, cmdObj);
+ }
+#endif
+ {
+ Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+ if (procNameObj) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
+ Jim_ListAppendElement(interp, listObj, procNameObj);
+ }
+ }
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
+
+ *objPtrPtr = listObj;
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return JIM_ERR;
+}
+
+
+static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
+ Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
+ return JIM_ERR;
+ }
+ else {
+ fputs(Jim_String(argv[2]), stdout);
+ }
+ }
+ else {
+ puts(Jim_String(argv[1]));
+ }
+ return JIM_OK;
+}
+
+
+static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res;
+ double doubleValue, doubleRes;
+ int i;
+
+ res = (op == JIM_EXPROP_ADD) ? 0 : 1;
+
+ for (i = 1; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
+ goto trydouble;
+ if (op == JIM_EXPROP_ADD)
+ res += wideValue;
+ else
+ res *= wideValue;
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ doubleRes = (double)res;
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_ADD)
+ doubleRes += doubleValue;
+ else
+ doubleRes *= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res = 0;
+ double doubleValue, doubleRes = 0;
+ int i = 2;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+ return JIM_ERR;
+ }
+ else if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ if (op == JIM_EXPROP_SUB)
+ doubleRes = -doubleValue;
+ else
+ doubleRes = 1.0 / doubleValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+ }
+ }
+ if (op == JIM_EXPROP_SUB) {
+ res = -wideValue;
+ Jim_SetResultInt(interp, res);
+ }
+ else {
+ doubleRes = 1.0 / wideValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ }
+ return JIM_OK;
+ }
+ else {
+ if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleRes)
+ != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ goto trydouble;
+ }
+ }
+ }
+ for (i = 2; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
+ doubleRes = (double)res;
+ goto trydouble;
+ }
+ if (op == JIM_EXPROP_SUB)
+ res -= wideValue;
+ else {
+ if (wideValue == 0) {
+ Jim_SetResultString(interp, "Division by zero", -1);
+ return JIM_ERR;
+ }
+ res /= wideValue;
+ }
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_SUB)
+ doubleRes -= doubleValue;
+ else
+ doubleRes /= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+
+static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
+}
+
+
+static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
+}
+
+
+static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
+}
+
+
+static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
+}
+
+
+static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!objPtr)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+}
+
+static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i = 1;
+ int complain = 1;
+
+ while (i < argc) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
+ i++;
+ break;
+ }
+ if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
+ complain = 0;
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ while (i < argc) {
+ if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
+ && complain) {
+ return JIM_ERR;
+ }
+ i++;
+ }
+
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+}
+
+static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
+{
+ if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
+ if (--interp->break_level > 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "condition body");
+ return JIM_ERR;
+ }
+
+
+ while (1) {
+ int boolean = 0, retval;
+
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
+ return retval;
+ if (!boolean)
+ break;
+
+ if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+ if (JimCheckLoopRetcode(interp, retval)) {
+ return retval;
+ }
+ switch (retval) {
+ case JIM_BREAK:
+ goto out;
+ case JIM_CONTINUE:
+ continue;
+ default:
+ return retval;
+ }
+ }
+ }
+ out:
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+}
+
+
+static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ int boolean = 1;
+ int immediate = 0;
+ Jim_Obj *varNamePtr = NULL;
+ Jim_Obj *stopVarNamePtr = NULL;
+
+ if (argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "start test next body");
+ return JIM_ERR;
+ }
+
+
+ if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
+ return retval;
+ }
+
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+
+
+#ifdef JIM_OPTIMIZATION
+ if (retval == JIM_OK && boolean) {
+ ScriptObj *incrScript;
+ struct ExprTree *expr;
+ jim_wide stop, currentVal;
+ Jim_Obj *objPtr;
+ int cmpOffset;
+
+
+ expr = JimGetExpression(interp, argv[2]);
+ incrScript = JimGetScript(interp, argv[3]);
+
+
+ if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
+ goto evalstart;
+ }
+
+ if (incrScript->token[1].type != JIM_TT_ESC) {
+ goto evalstart;
+ }
+
+ if (expr->expr->type == JIM_EXPROP_LT) {
+ cmpOffset = 0;
+ }
+ else if (expr->expr->type == JIM_EXPROP_LTE) {
+ cmpOffset = 1;
+ }
+ else {
+ goto evalstart;
+ }
+
+ if (expr->expr->left->type != JIM_TT_VAR) {
+ goto evalstart;
+ }
+
+ if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
+ goto evalstart;
+ }
+
+
+ if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
+ goto evalstart;
+ }
+
+
+ if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
+ goto evalstart;
+ }
+
+
+ if (expr->expr->right->type == JIM_TT_EXPR_INT) {
+ if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
+ goto evalstart;
+ }
+ }
+ else {
+ stopVarNamePtr = expr->expr->right->objPtr;
+ Jim_IncrRefCount(stopVarNamePtr);
+
+ stop = 0;
+ }
+
+
+ varNamePtr = expr->expr->left->objPtr;
+ Jim_IncrRefCount(varNamePtr);
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) {
+ goto testcond;
+ }
+
+
+ while (retval == JIM_OK) {
+
+
+
+
+ if (stopVarNamePtr) {
+ objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
+ goto testcond;
+ }
+ }
+
+ if (currentVal >= stop + cmpOffset) {
+ break;
+ }
+
+
+ retval = Jim_EvalObj(interp, argv[4]);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ immediate++;
+ goto out;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ retval = JIM_OK;
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
+
+
+ if (objPtr == NULL) {
+ retval = JIM_ERR;
+ goto out;
+ }
+ if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ currentVal = ++JimWideValue(objPtr);
+ Jim_InvalidateStringRep(objPtr);
+ }
+ else {
+ if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK ||
+ Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
+ ++currentVal)) != JIM_OK) {
+ goto evalnext;
+ }
+ }
+ }
+ }
+ goto out;
+ }
+ evalstart:
+#endif
+
+ while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
+
+ retval = Jim_EvalObj(interp, argv[4]);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ immediate++;
+ break;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+JIM_IF_OPTIM(evalnext:)
+ retval = Jim_EvalObj(interp, argv[3]);
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+JIM_IF_OPTIM(testcond:)
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+ }
+ }
+ }
+JIM_IF_OPTIM(out:)
+ if (stopVarNamePtr) {
+ Jim_DecrRefCount(interp, stopVarNamePtr);
+ }
+ if (varNamePtr) {
+ Jim_DecrRefCount(interp, varNamePtr);
+ }
+
+ if (!immediate) {
+ if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ }
+
+ return retval;
+}
+
+
+static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ jim_wide i;
+ jim_wide limit = 0;
+ jim_wide incr = 1;
+ Jim_Obj *bodyObjPtr;
+
+ if (argc < 4 || argc > 6) {
+ Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
+ return JIM_ERR;
+ }
+
+ retval = Jim_GetWideExpr(interp, argv[2], &i);
+ if (argc > 4 && retval == JIM_OK) {
+ retval = Jim_GetWideExpr(interp, argv[3], &limit);
+ }
+ if (argc > 5 && retval == JIM_OK) {
+ Jim_GetWideExpr(interp, argv[4], &incr);
+ }
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ if (argc == 4) {
+ limit = i;
+ i = 0;
+ }
+ bodyObjPtr = argv[argc - 1];
+
+ retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));
+
+ while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
+ retval = Jim_EvalObj(interp, bodyObjPtr);
+ if (JimCheckLoopRetcode(interp, retval)) {
+ return retval;
+ }
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+
+ retval = JIM_OK;
+
+
+ i += incr;
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ JimWideValue(objPtr) = i;
+ Jim_InvalidateStringRep(objPtr);
+
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ retval = JIM_ERR;
+ break;
+ }
+ }
+ }
+ else {
+ objPtr = Jim_NewIntObj(interp, i);
+ retval = Jim_SetVariable(interp, argv[1], objPtr);
+ if (retval != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ }
+ }
+ }
+ }
+
+ if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ return retval;
+}
+
+typedef struct {
+ Jim_Obj *objPtr;
+ int idx;
+} Jim_ListIter;
+
+static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
+{
+ iter->objPtr = objPtr;
+ iter->idx = 0;
+}
+
+static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
+ return NULL;
+ }
+ return iter->objPtr->internalRep.listValue.ele[iter->idx++];
+}
+
+static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ return iter->idx >= Jim_ListLength(interp, iter->objPtr);
+}
+
+
+static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
+{
+ int result = JIM_OK;
+ int i, numargs;
+ Jim_ListIter twoiters[2];
+ Jim_ListIter *iters;
+ Jim_Obj *script;
+ Jim_Obj *resultObj;
+
+ if (argc < 4 || argc % 2 != 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
+ return JIM_ERR;
+ }
+ script = argv[argc - 1];
+ numargs = (argc - 1 - 1);
+
+ if (numargs == 2) {
+ iters = twoiters;
+ }
+ else {
+ iters = Jim_Alloc(numargs * sizeof(*iters));
+ }
+ for (i = 0; i < numargs; i++) {
+ JimListIterInit(&iters[i], argv[i + 1]);
+ if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
+ result = JIM_ERR;
+ }
+ }
+ if (result != JIM_OK) {
+ Jim_SetResultString(interp, "foreach varlist is empty", -1);
+ goto empty_varlist;
+ }
+
+ if (doMap) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = interp->emptyObj;
+ }
+ Jim_IncrRefCount(resultObj);
+
+ while (1) {
+
+ for (i = 0; i < numargs; i += 2) {
+ if (!JimListIterDone(interp, &iters[i + 1])) {
+ break;
+ }
+ }
+ if (i == numargs) {
+
+ break;
+ }
+
+
+ for (i = 0; i < numargs; i += 2) {
+ Jim_Obj *varName;
+
+
+ JimListIterInit(&iters[i], argv[i + 1]);
+ while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
+ if (!valObj) {
+
+ valObj = interp->emptyObj;
+ }
+
+ Jim_IncrRefCount(valObj);
+ result = Jim_SetVariable(interp, varName, valObj);
+ Jim_DecrRefCount(interp, valObj);
+ if (result != JIM_OK) {
+ goto err;
+ }
+ }
+ }
+ result = Jim_EvalObj(interp, script);
+ if (JimCheckLoopRetcode(interp, result)) {
+ goto err;
+ }
+ switch (result) {
+ case JIM_OK:
+ if (doMap) {
+ Jim_ListAppendElement(interp, resultObj, interp->result);
+ }
+ break;
+ case JIM_CONTINUE:
+ break;
+ case JIM_BREAK:
+ goto out;
+ default:
+ goto err;
+ }
+ }
+ out:
+ result = JIM_OK;
+ Jim_SetResult(interp, resultObj);
+ err:
+ Jim_DecrRefCount(interp, resultObj);
+ empty_varlist:
+ if (numargs > 2) {
+ Jim_Free(iters);
+ }
+ return result;
+}
+
+
+static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 0);
+}
+
+
+static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 1);
+}
+
+
+static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int result = JIM_ERR;
+ int i;
+ Jim_ListIter iter;
+ Jim_Obj *resultObj;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
+ return JIM_ERR;
+ }
+
+ JimListIterInit(&iter, argv[1]);
+
+ for (i = 2; i < argc; i++) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iter);
+ result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
+ if (result != JIM_OK) {
+ return result;
+ }
+ }
+
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ while (!JimListIterDone(interp, &iter)) {
+ Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
+ }
+
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+
+static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int boolean, retval, current = 1, falsebody = 0;
+
+ if (argc >= 3) {
+ while (1) {
+
+ if (current >= argc)
+ goto err;
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
+ != JIM_OK)
+ return retval;
+
+ if (current >= argc)
+ goto err;
+ if (Jim_CompareStringImmediate(interp, argv[current], "then"))
+ current++;
+
+ if (current >= argc)
+ goto err;
+ if (boolean)
+ return Jim_EvalObj(interp, argv[current]);
+
+ if (++current >= argc) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ return JIM_OK;
+ }
+ falsebody = current++;
+ if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
+
+ if (current != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[current]);
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
+ continue;
+
+ else if (falsebody != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[falsebody]);
+ }
+ return JIM_OK;
+ }
+ err:
+ Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
+ return JIM_ERR;
+}
+
+
+int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
+ Jim_Obj *stringObj, int flags)
+{
+ Jim_Obj *parms[5];
+ int argc = 0;
+ long eq;
+ int rc;
+
+ parms[argc++] = commandObj;
+ if (flags & JIM_NOCASE) {
+ parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
+ }
+ if (flags & JIM_OPT_END) {
+ parms[argc++] = Jim_NewStringObj(interp, "--", -1);
+ }
+ parms[argc++] = patternObj;
+ parms[argc++] = stringObj;
+
+ rc = Jim_EvalObjVector(interp, argc, parms);
+
+ if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
+ eq = -rc;
+ }
+
+ return eq;
+}
+
+
+static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
+ int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+ int match_flags = 0;
+ Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
+ Jim_Obj **caseList;
+
+ if (argc < 3) {
+ wrongnumargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string "
+ "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
+ return JIM_ERR;
+ }
+ for (opt = 1; opt < argc; ++opt) {
+ const char *option = Jim_String(argv[opt]);
+
+ if (*option != '-')
+ break;
+ else if (strncmp(option, "--", 2) == 0) {
+ ++opt;
+ break;
+ }
+ else if (strncmp(option, "-exact", 2) == 0)
+ matchOpt = SWITCH_EXACT;
+ else if (strncmp(option, "-glob", 2) == 0)
+ matchOpt = SWITCH_GLOB;
+ else if (strncmp(option, "-regexp", 2) == 0) {
+ matchOpt = SWITCH_RE;
+ match_flags |= JIM_OPT_END;
+ }
+ else if (strncmp(option, "-command", 2) == 0) {
+ matchOpt = SWITCH_CMD;
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ command = argv[++opt];
+ }
+ else {
+ Jim_SetResultFormatted(interp,
+ "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
+ argv[opt]);
+ return JIM_ERR;
+ }
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ }
+ strObj = argv[opt++];
+ patCount = argc - opt;
+ if (patCount == 1) {
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
+ }
+ else
+ caseList = (Jim_Obj **)&argv[opt];
+ if (patCount == 0 || patCount % 2 != 0)
+ goto wrongnumargs;
+ for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
+ Jim_Obj *patObj = caseList[i];
+
+ if (!Jim_CompareStringImmediate(interp, patObj, "default")
+ || i < (patCount - 2)) {
+ switch (matchOpt) {
+ case SWITCH_EXACT:
+ if (Jim_StringEqObj(strObj, patObj))
+ scriptObj = caseList[i + 1];
+ break;
+ case SWITCH_GLOB:
+ if (Jim_StringMatchObj(interp, patObj, strObj, 0))
+ scriptObj = caseList[i + 1];
+ break;
+ case SWITCH_RE:
+ command = Jim_NewStringObj(interp, "regexp", -1);
+
+ case SWITCH_CMD:{
+ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);
+
+ if (argc - opt == 1) {
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
+ }
+
+ if (rc < 0) {
+ return -rc;
+ }
+ if (rc)
+ scriptObj = caseList[i + 1];
+ break;
+ }
+ }
+ }
+ else {
+ scriptObj = caseList[i + 1];
+ }
+ }
+ for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
+ scriptObj = caseList[i + 1];
+ if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
+ Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
+ return JIM_ERR;
+ }
+ Jim_SetEmptyResult(interp);
+ if (scriptObj) {
+ return Jim_EvalObj(interp, scriptObj);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+
+ listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int ret;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
+ return JIM_ERR;
+ }
+ ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
+ if (ret < 0) {
+ ret = JIM_OK;
+ Jim_SetEmptyResult(interp);
+ }
+ else if (ret == JIM_OK) {
+ Jim_SetResult(interp, objPtr);
+ }
+ return ret;
+}
+
+
+static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
+ return JIM_OK;
+}
+
+
+static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
+ "-stride", "-index", NULL
+ };
+ enum
+ { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
+ OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
+ int i;
+ int opt_bool = 0;
+ int opt_not = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ int opt_match = OPT_EXACT;
+ int listlen;
+ int rc = JIM_OK;
+ Jim_Obj *listObjPtr = NULL;
+ Jim_Obj *commandObj = NULL;
+ Jim_Obj *indexObj = NULL;
+ int match_flags = 0;
+ long stride = 1;
+
+ if (argc < 3) {
+ wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc - 2; i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_BOOL:
+ opt_bool = 1;
+ opt_inline = 0;
+ break;
+ case OPT_NOT:
+ opt_not = 1;
+ break;
+ case OPT_NOCASE:
+ match_flags |= JIM_NOCASE;
+ break;
+ case OPT_INLINE:
+ opt_inline = 1;
+ opt_bool = 0;
+ break;
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+ case OPT_REGEXP:
+ opt_match = option;
+ match_flags |= JIM_OPT_END;
+ break;
+ case OPT_COMMAND:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ commandObj = argv[++i];
+
+ case OPT_EXACT:
+ case OPT_GLOB:
+ opt_match = option;
+ break;
+ case OPT_INDEX:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ indexObj = argv[++i];
+ break;
+ case OPT_STRIDE:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (stride < 1) {
+ Jim_SetResultString(interp, "stride length must be at least 1", -1);
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+
+ argc -= i;
+ if (argc < 2) {
+ goto wrongargs;
+ }
+ argv += i;
+
+ listlen = Jim_ListLength(interp, argv[0]);
+ if (listlen % stride) {
+ Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+ return JIM_ERR;
+ }
+
+ if (opt_all) {
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ }
+ if (opt_match == OPT_REGEXP) {
+ commandObj = Jim_NewStringObj(interp, "regexp", -1);
+ }
+ if (commandObj) {
+ Jim_IncrRefCount(commandObj);
+ }
+
+ for (i = 0; i < listlen; i += stride) {
+ int eq = 0;
+ Jim_Obj *searchListObj;
+ Jim_Obj *objPtr;
+ int offset;
+
+ if (indexObj) {
+ int indexlen = Jim_ListLength(interp, indexObj);
+ if (stride == 1) {
+ searchListObj = Jim_ListGetIndex(interp, argv[0], i);
+ }
+ else {
+ searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
+ }
+ Jim_IncrRefCount(searchListObj);
+ rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
+ if (rc != JIM_OK) {
+ Jim_DecrRefCount(interp, searchListObj);
+ rc = JIM_ERR;
+ goto done;
+ }
+
+ offset = 0;
+ }
+ else {
+
+ searchListObj = argv[0];
+ offset = i;
+ objPtr = Jim_ListGetIndex(interp, searchListObj, i);
+ Jim_IncrRefCount(searchListObj);
+ }
+
+ switch (opt_match) {
+ case OPT_EXACT:
+ eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
+ break;
+
+ case OPT_GLOB:
+ eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
+ break;
+
+ case OPT_REGEXP:
+ case OPT_COMMAND:
+ eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
+ if (eq < 0) {
+ Jim_DecrRefCount(interp, searchListObj);
+ rc = JIM_ERR;
+ goto done;
+ }
+ break;
+ }
+
+
+ if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
+ Jim_Obj *resultObj;
+
+ if (opt_bool) {
+ resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
+ }
+ else if (!opt_inline) {
+ resultObj = Jim_NewIntObj(interp, i);
+ }
+ else if (stride == 1) {
+ resultObj = objPtr;
+ }
+ else if (opt_all) {
+
+ ListInsertElements(listObjPtr, -1, stride,
+ searchListObj->internalRep.listValue.ele + offset);
+
+ resultObj = NULL;
+ }
+ else {
+ resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
+ }
+
+ if (opt_all) {
+
+ if (stride == 1) {
+ Jim_ListAppendElement(interp, listObjPtr, resultObj);
+ }
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ Jim_DecrRefCount(interp, searchListObj);
+ goto done;
+ }
+ }
+ Jim_DecrRefCount(interp, searchListObj);
+ }
+
+ if (opt_all) {
+ Jim_SetResult(interp, listObjPtr);
+ listObjPtr = NULL;
+ }
+ else {
+
+ if (opt_bool) {
+ Jim_SetResultBool(interp, opt_not);
+ }
+ else if (!opt_inline) {
+ Jim_SetResultInt(interp, -1);
+ }
+ }
+
+ done:
+ if (listObjPtr) {
+ Jim_FreeNewObj(interp, listObjPtr);
+ }
+ if (commandObj) {
+ Jim_DecrRefCount(interp, commandObj);
+ }
+ return rc;
+}
+
+
+static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+ int new_obj = 0;
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+ return JIM_ERR;
+ }
+ listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!listObjPtr) {
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ new_obj = 1;
+ }
+ else if (Jim_IsShared(listObjPtr)) {
+ listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
+ new_obj = 1;
+ }
+ for (i = 2; i < argc; i++)
+ Jim_ListAppendElement(interp, listObjPtr, argv[i]);
+ if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+ if (new_obj)
+ Jim_FreeNewObj(interp, listObjPtr);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int idx, len;
+ Jim_Obj *listPtr;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
+ return JIM_ERR;
+ }
+ listPtr = argv[1];
+ if (Jim_IsShared(listPtr))
+ listPtr = Jim_DuplicateObj(interp, listPtr);
+ if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
+ goto err;
+ len = Jim_ListLength(interp, listPtr);
+ if (idx >= len)
+ idx = len;
+ else if (idx < 0)
+ idx = len + idx + 1;
+ Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
+ Jim_SetResult(interp, listPtr);
+ return JIM_OK;
+ err:
+ if (listPtr != argv[1]) {
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int first, last, len, rangeLen;
+ Jim_Obj *listObj;
+ Jim_Obj *newListObj;
+
+ if (argc < 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
+ Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ listObj = argv[1];
+ len = Jim_ListLength(interp, listObj);
+
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+
+
+ if (first > len) {
+ first = len;
+ }
+
+
+ newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
+
+
+ ListInsertElements(newListObj, -1, argc - 4, argv + 4);
+
+
+ ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
+
+ Jim_SetResult(interp, newListObj);
+ return JIM_OK;
+}
+
+
+static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
+ return JIM_ERR;
+ }
+ else if (argc == 3) {
+
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+ }
+ return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
+}
+
+
+static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
+{
+ static const char * const options[] = {
+ "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
+ "-stride", "-dictionary", NULL
+ };
+ enum {
+ OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
+ OPT_STRIDE, OPT_DICT
+ };
+ Jim_Obj *resObj;
+ int i;
+ int retCode;
+ int shared;
+ long stride = 1;
+ Jim_Obj **elements;
+ int listlen;
+
+ struct lsort_info info;
+
+ if (argc < 2) {
+wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?options? list");
+ return JIM_ERR;
+ }
+
+ info.type = JIM_LSORT_ASCII;
+ info.order = 1;
+ info.indexc = 0;
+ info.unique = 0;
+ info.command = NULL;
+ info.interp = interp;
+
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
+ != JIM_OK)
+ return JIM_ERR;
+ switch (option) {
+ case OPT_ASCII:
+ info.type = JIM_LSORT_ASCII;
+ break;
+ case OPT_DICT:
+ info.type = JIM_LSORT_DICT;
+ break;
+ case OPT_NOCASE:
+ info.type = JIM_LSORT_NOCASE;
+ break;
+ case OPT_INTEGER:
+ info.type = JIM_LSORT_INTEGER;
+ break;
+ case OPT_REAL:
+ info.type = JIM_LSORT_REAL;
+ break;
+ case OPT_INCREASING:
+ info.order = 1;
+ break;
+ case OPT_DECREASING:
+ info.order = -1;
+ break;
+ case OPT_UNIQUE:
+ info.unique = 1;
+ break;
+ case OPT_COMMAND:
+ if (i >= (argc - 2)) {
+ Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
+ return JIM_ERR;
+ }
+ info.type = JIM_LSORT_COMMAND;
+ info.command = argv[i + 1];
+ i++;
+ break;
+ case OPT_STRIDE:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (stride < 2) {
+ Jim_SetResultString(interp, "stride length must be at least 2", -1);
+ return JIM_ERR;
+ }
+ break;
+ case OPT_INDEX:
+ if (i >= (argc - 2)) {
+badindex:
+ Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
+ return JIM_ERR;
+ }
+ JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
+ if (info.indexc == 0) {
+ goto badindex;
+ }
+ i++;
+ break;
+ }
+ }
+ resObj = argv[argc - 1];
+ JimListGetElements(interp, resObj, &listlen, &elements);
+ if (listlen <= 1) {
+
+ Jim_SetResult(interp, resObj);
+ return JIM_OK;
+ }
+
+ if (stride > 1) {
+ Jim_Obj *tmpListObj;
+ int i;
+
+ if (listlen % stride) {
+ Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+ return JIM_ERR;
+ }
+
+ tmpListObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_IncrRefCount(tmpListObj);
+ for (i = 0; i < listlen; i += stride) {
+ Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
+ }
+ retCode = ListSortElements(interp, tmpListObj, &info);
+ if (retCode == JIM_OK) {
+ resObj = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < listlen; i += stride) {
+ Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
+ }
+ Jim_SetResult(interp, resObj);
+ }
+ Jim_DecrRefCount(interp, tmpListObj);
+ }
+ else {
+ if ((shared = Jim_IsShared(resObj))) {
+ resObj = Jim_DuplicateObj(interp, resObj);
+ }
+ retCode = ListSortElements(interp, resObj, &info);
+ if (retCode == JIM_OK) {
+ Jim_SetResult(interp, resObj);
+ }
+ else if (shared) {
+ Jim_FreeNewObj(interp, resObj);
+ }
+ }
+ return retCode;
+}
+
+
+static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *stringObjPtr;
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!stringObjPtr)
+ return JIM_ERR;
+ }
+ else {
+ int new_obj = 0;
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!stringObjPtr) {
+
+ stringObjPtr = Jim_NewEmptyStringObj(interp);
+ new_obj = 1;
+ }
+ else if (Jim_IsShared(stringObjPtr)) {
+ new_obj = 1;
+ stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+ }
+ for (i = 2; i < argc; i++) {
+ Jim_AppendObj(interp, stringObjPtr, argv[i]);
+ }
+ if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+ if (new_obj) {
+ Jim_FreeNewObj(interp, stringObjPtr);
+ }
+ return JIM_ERR;
+ }
+ }
+ Jim_SetResult(interp, stringObjPtr);
+ return JIM_OK;
+}
+
+
+
+
+
+static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int rc;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ rc = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ }
+
+ return rc;
+}
+
+
+static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc >= 2) {
+ int retcode;
+ Jim_CallFrame *savedCallFrame, *targetCallFrame;
+ const char *str;
+
+
+ savedCallFrame = interp->framePtr;
+
+
+ str = Jim_String(argv[1]);
+ if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+
+ interp->framePtr = targetCallFrame;
+ if (argc == 2) {
+ retcode = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ }
+ interp->framePtr = savedCallFrame;
+ return retcode;
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+}
+
+
+static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (argc == 2) {
+ retcode = Jim_EvalExpression(interp, argv[1]);
+ }
+#ifndef JIM_COMPAT
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "expression");
+ retcode = JIM_ERR;
+ }
+#else
+ else if (argc > 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_EvalExpression(interp, objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
+ return JIM_ERR;
+ }
+#endif
+ return retcode;
+}
+
+static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
+{
+ if (argc != 1 && argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?level?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ long level;
+ int ret = Jim_GetLong(interp, argv[1], &level);
+ if (ret != JIM_OK) {
+ return ret;
+ }
+ interp->break_level = level;
+ }
+ return retcode;
+}
+
+
+static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
+}
+
+
+static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
+}
+
+
+static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObj;
+ int i;
+ jim_wide skip = 0;
+ jim_wide last = 0;
+
+ if (argc > 1) {
+ if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ if (argc > 2) {
+ if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = skip; i <= interp->procLevel; i++) {
+ Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+ if (frame->procLevel < last) {
+ break;
+ }
+ JimAddStackFrame(interp, frame, listObj);
+ }
+ Jim_SetResult(interp, listObj);
+ return JIM_OK;
+}
+
+
+static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_Obj *stackTraceObj = NULL;
+ Jim_Obj *errorCodeObj = NULL;
+ int returnCode = JIM_OK;
+ long level = 1;
+
+ for (i = 1; i < argc - 1; i += 2) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
+ if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
+ stackTraceObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
+ errorCodeObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
+ if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
+ return JIM_ERR;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i != argc - 1 && i != argc) {
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
+ }
+
+
+ if (stackTraceObj && returnCode == JIM_ERR) {
+ JimSetStackTrace(interp, stackTraceObj);
+ }
+
+ if (errorCodeObj && returnCode == JIM_ERR) {
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
+ }
+ interp->returnCode = returnCode;
+ interp->returnLevel = level;
+
+ if (i == argc - 1) {
+ Jim_SetResult(interp, argv[i]);
+ }
+ return level == 0 ? returnCode : JIM_RETURN;
+}
+
+
+static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (interp->framePtr->level == 0) {
+ Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
+ return JIM_ERR;
+ }
+ else if (argc >= 2) {
+
+ Jim_CallFrame *cf = interp->framePtr->parent;
+
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+ if (cmdPtr == NULL) {
+ return JIM_ERR;
+ }
+
+ JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
+
+
+ JimIncrCmdRefCount(cmdPtr);
+ cf->tailcallCmd = cmdPtr;
+
+
+ JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
+
+ cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_IncrRefCount(cf->tailcallObj);
+
+
+ return JIM_EVAL;
+ }
+ return JIM_OK;
+}
+
+static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdList;
+ Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
+
+
+ cmdList = Jim_DuplicateObj(interp, prefixListObj);
+ Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
+
+ return JimEvalObjList(interp, cmdList);
+}
+
+static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
+{
+ Jim_Obj *prefixListObj = privData;
+ Jim_DecrRefCount(interp, prefixListObj);
+}
+
+static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *prefixListObj;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
+ return JIM_ERR;
+ }
+
+ prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
+ Jim_IncrRefCount(prefixListObj);
+ Jim_SetResult(interp, argv[1]);
+
+ return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
+}
+
+
+static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Cmd *cmd;
+
+ if (argc != 4 && argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
+ return JIM_ERR;
+ }
+
+ if (argc == 4) {
+ cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
+ }
+ else {
+ cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
+ }
+
+ if (cmd) {
+
+ Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
+ JimCreateCommand(interp, nameObjPtr, cmd);
+
+
+ JimUpdateProcNamespace(interp, cmd, nameObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+
+
+ Jim_SetResult(interp, argv[1]);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "callback");
+ return JIM_ERR;
+ }
+
+ if (interp->traceCmdObj) {
+ Jim_DecrRefCount(interp, interp->traceCmdObj);
+ interp->traceCmdObj = NULL;
+ }
+
+ if (Jim_Length(argv[1])) {
+
+ interp->traceCmdObj = argv[1];
+ Jim_IncrRefCount(interp->traceCmdObj);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+ return JIM_ERR;
+ }
+
+
+ interp->local++;
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+ interp->local--;
+
+
+
+ if (retcode == 0) {
+ Jim_Obj *cmdNameObj = Jim_GetResult(interp);
+
+ if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
+ return JIM_ERR;
+ }
+ if (interp->framePtr->localCommands == NULL) {
+ interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
+ Jim_InitStack(interp->framePtr->localCommands);
+ }
+ Jim_IncrRefCount(cmdNameObj);
+ Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
+ }
+
+ return retcode;
+}
+
+
+static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+ return JIM_ERR;
+ }
+ else {
+ int retcode;
+
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+ if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
+ Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
+ return JIM_ERR;
+ }
+
+ cmdPtr->u.proc.upcall++;
+ JimIncrCmdRefCount(cmdPtr);
+
+
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+
+
+ cmdPtr->u.proc.upcall--;
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+ return retcode;
+ }
+}
+
+
+static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
+ return JIM_ERR;
+ }
+ else {
+ int ret;
+ Jim_Cmd *cmd;
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_Obj *nsObj = NULL;
+ Jim_Obj **nargv;
+
+ int len = Jim_ListLength(interp, argv[1]);
+ if (len != 2 && len != 3) {
+ Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
+ return JIM_ERR;
+ }
+
+ if (len == 3) {
+#ifdef jim_ext_namespace
+
+ nsObj = Jim_ListGetIndex(interp, argv[1], 2);
+#else
+ Jim_SetResultString(interp, "namespaces not enabled", -1);
+ return JIM_ERR;
+#endif
+ }
+ argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
+ bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
+
+ cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
+
+ if (cmd) {
+
+ nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
+ nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
+ Jim_IncrRefCount(nargv[0]);
+ memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
+ ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
+ Jim_DecrRefCount(interp, nargv[0]);
+ Jim_Free(nargv);
+
+ JimDecrCmdRefCount(interp, cmd);
+ return ret;
+ }
+ return JIM_ERR;
+ }
+}
+
+
+
+static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ return JIM_OK;
+}
+
+
+static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_CallFrame *targetCallFrame;
+
+
+ if (argc > 3 && (argc % 2 == 0)) {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
+ return JIM_ERR;
+ }
+
+
+ for (i = 1; i < argc; i += 2) {
+ if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
+ return JIM_ERR;
+ }
+
+ if (interp->framePtr->level == 0)
+ return JIM_OK;
+ for (i = 1; i < argc; i++) {
+
+ const char *name = Jim_String(argv[i]);
+ if (name[0] != ':' || name[1] != ':') {
+ if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
+ Jim_Obj *objPtr, int nocase)
+{
+ int numMaps;
+ const char *str, *noMatchStart = NULL;
+ int strLen, i;
+ Jim_Obj *resultObjPtr;
+
+ numMaps = Jim_ListLength(interp, mapListObjPtr);
+ if (numMaps % 2) {
+ Jim_SetResultString(interp, "list must contain an even number of elements", -1);
+ return NULL;
+ }
+
+ str = Jim_String(objPtr);
+ strLen = Jim_Utf8Length(interp, objPtr);
+
+
+ resultObjPtr = Jim_NewStringObj(interp, "", 0);
+ while (strLen) {
+ for (i = 0; i < numMaps; i += 2) {
+ Jim_Obj *eachObjPtr;
+ const char *k;
+ int kl;
+
+ eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
+ k = Jim_String(eachObjPtr);
+ kl = Jim_Utf8Length(interp, eachObjPtr);
+
+ if (strLen >= kl && kl) {
+ int rc;
+ rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
+ if (rc == 0) {
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ noMatchStart = NULL;
+ }
+ Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
+ str += utf8_index(str, kl);
+ strLen -= kl;
+ break;
+ }
+ }
+ }
+ if (i == numMaps) {
+ int c;
+ if (noMatchStart == NULL)
+ noMatchStart = str;
+ str += utf8_tounicode(str, &c);
+ strLen--;
+ }
+ }
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ }
+ return resultObjPtr;
+}
+
+
+static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int len;
+ int opt_case = 1;
+ int option;
+ static const char * const nocase_options[] = {
+ "-nocase", NULL
+ };
+ static const char * const nocase_length_options[] = {
+ "-nocase", "-length", NULL
+ };
+
+ enum {
+ OPT_BYTELENGTH,
+ OPT_BYTERANGE,
+ OPT_CAT,
+ OPT_COMPARE,
+ OPT_EQUAL,
+ OPT_FIRST,
+ OPT_INDEX,
+ OPT_IS,
+ OPT_LAST,
+ OPT_LENGTH,
+ OPT_MAP,
+ OPT_MATCH,
+ OPT_RANGE,
+ OPT_REPEAT,
+ OPT_REPLACE,
+ OPT_REVERSE,
+ OPT_TOLOWER,
+ OPT_TOTITLE,
+ OPT_TOUPPER,
+ OPT_TRIM,
+ OPT_TRIMLEFT,
+ OPT_TRIMRIGHT,
+ OPT_COUNT
+ };
+ static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+ JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
+ JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
+ JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
+ JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
+ JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
+ JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
+ JIM_DEF_SUBCMD("index", "string index", 2, 2),
+ JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
+ JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
+ JIM_DEF_SUBCMD("length","string", 1, 1),
+ JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
+ JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
+ JIM_DEF_SUBCMD("range", "string first last", 3, 3),
+ JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
+ JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
+ JIM_DEF_SUBCMD("reverse", "string", 1, 1),
+ JIM_DEF_SUBCMD("tolower", "string", 1, 1),
+ JIM_DEF_SUBCMD("totitle", "string", 1, 1),
+ JIM_DEF_SUBCMD("toupper", "string", 1, 1),
+ JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
+ JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
+ JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
+ { NULL }
+ };
+ const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+ option = ct - cmds;
+
+ switch (option) {
+ case OPT_LENGTH:
+ Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_BYTELENGTH:
+ Jim_SetResultInt(interp, Jim_Length(argv[2]));
+ return JIM_OK;
+
+ case OPT_CAT:{
+ Jim_Obj *objPtr;
+ if (argc == 3) {
+
+ objPtr = argv[2];
+ }
+ else {
+ int i;
+
+ objPtr = Jim_NewStringObj(interp, "", 0);
+
+ for (i = 2; i < argc; i++) {
+ Jim_AppendObj(interp, objPtr, argv[i]);
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_COMPARE:
+ case OPT_EQUAL:
+ {
+
+ long opt_length = -1;
+ int n = argc - 4;
+ int i = 2;
+ while (n > 0) {
+ int subopt;
+ if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK) {
+badcompareargs:
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ if (subopt == 0) {
+
+ opt_case = 0;
+ n--;
+ }
+ else {
+
+ if (n < 2) {
+ goto badcompareargs;
+ }
+ if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
+ return JIM_ERR;
+ }
+ n -= 2;
+ }
+ }
+ if (n) {
+ goto badcompareargs;
+ }
+ argv += argc - 2;
+ if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
+
+ Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
+ }
+ else {
+ const char *s1 = Jim_String(argv[0]);
+ int l1 = Jim_Utf8Length(interp, argv[0]);
+ const char *s2 = Jim_String(argv[1]);
+ int l2 = Jim_Utf8Length(interp, argv[1]);
+ if (opt_length >= 0) {
+ if (l1 > opt_length) {
+ l1 = opt_length;
+ }
+ if (l2 > opt_length) {
+ l2 = opt_length;
+ }
+ }
+ n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
+ Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
+ }
+ return JIM_OK;
+ }
+
+ case OPT_MATCH:
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
+ return JIM_ERR;
+ }
+ if (opt_case == 0) {
+ argv++;
+ }
+ Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
+ return JIM_OK;
+
+ case OPT_MAP:{
+ Jim_Obj *objPtr;
+
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
+ return JIM_ERR;
+ }
+
+ if (opt_case == 0) {
+ argv++;
+ }
+ objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_RANGE:{
+ Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_BYTERANGE:{
+ Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REPLACE:{
+ Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+
+ case OPT_REPEAT:{
+ Jim_Obj *objPtr;
+ jim_wide count;
+
+ if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewStringObj(interp, "", 0);
+ if (count > 0) {
+ while (count--) {
+ Jim_AppendObj(interp, objPtr, argv[2]);
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REVERSE:{
+ char *buf, *p;
+ const char *str;
+ int i;
+
+ str = Jim_GetString(argv[2], &len);
+ buf = Jim_Alloc(len + 1);
+ assert(buf);
+ p = buf + len;
+ *p = 0;
+ for (i = 0; i < len; ) {
+ int c;
+ int l = utf8_tounicode(str, &c);
+ memcpy(p - l, str, l);
+ p -= l;
+ i += l;
+ str += l;
+ }
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+ return JIM_OK;
+ }
+
+ case OPT_INDEX:{
+ int idx;
+ const char *str;
+
+ if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ str = Jim_String(argv[2]);
+ len = Jim_Utf8Length(interp, argv[2]);
+ idx = JimRelToAbsIndex(len, idx);
+ if (idx < 0 || idx >= len || str == NULL) {
+ Jim_SetResultString(interp, "", 0);
+ }
+ else if (len == Jim_Length(argv[2])) {
+
+ Jim_SetResultString(interp, str + idx, 1);
+ }
+ else {
+ int c;
+ int i = utf8_index(str, idx);
+ Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
+ }
+ return JIM_OK;
+ }
+
+ case OPT_FIRST:
+ case OPT_LAST:{
+ int idx = 0, l1, l2;
+ const char *s1, *s2;
+
+ s1 = Jim_String(argv[2]);
+ s2 = Jim_String(argv[3]);
+ l1 = Jim_Utf8Length(interp, argv[2]);
+ l2 = Jim_Utf8Length(interp, argv[3]);
+ if (argc == 5) {
+ if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ idx = JimRelToAbsIndex(l2, idx);
+ if (idx < 0) {
+ idx = 0;
+ }
+ }
+ else if (option == OPT_LAST) {
+ idx = l2;
+ }
+ if (option == OPT_FIRST) {
+ Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
+ }
+ else {
+#ifdef JIM_UTF8
+ Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
+#else
+ Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
+#endif
+ }
+ return JIM_OK;
+ }
+
+ case OPT_TRIM:
+ Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ case OPT_TRIMLEFT:
+ Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ case OPT_TRIMRIGHT:{
+ Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
+ return JIM_OK;
+ }
+
+ case OPT_TOLOWER:
+ Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
+ return JIM_OK;
+ case OPT_TOUPPER:
+ Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
+ return JIM_OK;
+ case OPT_TOTITLE:
+ Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_IS:
+ if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long i, count = 1;
+ jim_wide start, elapsed;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
+ return JIM_ERR;
+ }
+ if (count < 0)
+ return JIM_OK;
+ i = count;
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ while (i-- > 0) {
+ int retval;
+
+ retval = Jim_EvalObj(interp, argv[1]);
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ }
+ elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (elapsed < count * 10) {
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
+ }
+ else {
+ Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
+ }
+ Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
+ return JIM_OK;
+}
+
+
+static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long us = 0;
+ jim_wide start, delta, overhead;
+ Jim_Obj *objPtr;
+ double us_per_iter;
+ int count;
+ int n;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
+ return JIM_ERR;
+ us *= 1000;
+ }
+ if (us < 1) {
+
+ us = 1000 * 1000;
+ }
+
+
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ count = 0;
+ do {
+ int retval = Jim_EvalObj(interp, argv[1]);
+ delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ count++;
+ } while (delta < us);
+
+
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+ n = 0;
+ do {
+ int retval = Jim_EvalObj(interp, interp->nullScriptObj);
+ overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ n++;
+ } while (n < count);
+
+ delta -= overhead;
+
+ us_per_iter = (double)delta / count;
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
+ Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long exitCode = 0;
+
+ if (argc > 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[1]);
+ }
+ interp->exitCode = exitCode;
+ return JIM_EXIT;
+}
+
+static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
+{
+ int len = Jim_ListLength(interp, retcodeListObj);
+ int i;
+ for (i = 0; i < len; i++) {
+ int returncode;
+ if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (rc == returncode) {
+ return JIM_OK;
+ }
+ }
+ return -1;
+}
+
+
+static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
+{
+ static const char * const wrongargs_catchtry[2] = {
+ "?-?no?code ... --? script ?resultVarName? ?optionVarName?",
+ "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
+ };
+ int exitCode = 0;
+ int i;
+ int sig = 0;
+ int ok;
+ Jim_Obj *finallyScriptObj = NULL;
+ Jim_Obj *msgVarObj = NULL;
+ Jim_Obj *optsVarObj = NULL;
+ Jim_Obj *handlerScriptObj = NULL;
+ Jim_Obj *errorCodeObj;
+ int idx;
+
+
+ jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+ static const int max_ignore_code = sizeof(ignore_mask) * 8;
+
+ JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
+
+ Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
+
+ for (i = 1; i < argc - 1; i++) {
+ const char *arg = Jim_String(argv[i]);
+ jim_wide option;
+ int ignore;
+
+
+ if (strcmp(arg, "--") == 0) {
+ i++;
+ break;
+ }
+ if (*arg != '-') {
+ break;
+ }
+
+ if (strncmp(arg, "-no", 3) == 0) {
+ arg += 3;
+ ignore = 1;
+ }
+ else {
+ arg++;
+ ignore = 0;
+ }
+
+ if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+ option = -1;
+ }
+ if (option < 0) {
+ option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+ }
+ if (option < 0) {
+ goto wrongargs;
+ }
+
+ if (ignore) {
+ ignore_mask |= ((jim_wide)1 << option);
+ }
+ else {
+ ignore_mask &= (~((jim_wide)1 << option));
+ }
+ }
+
+ idx = i;
+
+ if (argc - idx < 1) {
+wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
+ return JIM_ERR;
+ }
+
+ if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
+ sig++;
+ }
+
+ interp->signal_level += sig;
+ if (Jim_CheckSignal(interp)) {
+
+ exitCode = JIM_SIGNAL;
+ }
+ else {
+ exitCode = Jim_EvalObj(interp, argv[idx]);
+
+ interp->errorFlag = 0;
+ }
+ interp->signal_level -= sig;
+
+ errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+
+ idx++;
+ if (istry) {
+ while (idx < argc) {
+ int option;
+ int ret;
+ static const char * const try_options[] = { "on", "trap", "finally", NULL };
+ enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
+
+ if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case TRY_ON:
+ case TRY_TRAP:
+ if (idx + 4 > argc) {
+ goto wrongargs;
+ }
+ if (option == TRY_ON) {
+ ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
+ if (ret > JIM_OK) {
+ goto wrongargs;
+ }
+ }
+ else if (errorCodeObj) {
+ int len = Jim_ListLength(interp, argv[idx + 1]);
+ int i;
+
+ ret = JIM_OK;
+
+ for (i = 0; i < len; i++) {
+ Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
+ if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
+ ret = -1;
+ break;
+ }
+ }
+ }
+ else {
+
+ ret = -1;
+ }
+
+ if (ret == JIM_OK && handlerScriptObj == NULL) {
+ msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
+ optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
+ handlerScriptObj = argv[idx + 3];
+ }
+ idx += 4;
+ break;
+ case TRY_FINALLY:
+ if (idx + 2 != argc) {
+ goto wrongargs;
+ }
+ finallyScriptObj = argv[idx + 1];
+ idx += 2;
+ break;
+ }
+ }
+ }
+ else {
+ if (argc - idx >= 1) {
+ msgVarObj = argv[idx];
+ idx++;
+ if (argc - idx >= 1) {
+ optsVarObj = argv[idx];
+ idx++;
+ }
+ }
+ }
+
+
+ if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
+
+ if (finallyScriptObj) {
+ Jim_EvalObj(interp, finallyScriptObj);
+ }
+ return exitCode;
+ }
+
+ if (sig && exitCode == JIM_SIGNAL) {
+
+ if (interp->signal_set_result) {
+ interp->signal_set_result(interp, interp->sigmask);
+ }
+ else if (!istry) {
+ Jim_SetResultInt(interp, interp->sigmask);
+ }
+ interp->sigmask = 0;
+ }
+
+ ok = 1;
+ if (msgVarObj && Jim_Length(msgVarObj)) {
+ if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
+ ok = 0;
+ }
+ }
+ if (ok && optsVarObj && Jim_Length(optsVarObj)) {
+ Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+ Jim_ListAppendElement(interp, optListObj,
+ Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+ if (exitCode == JIM_ERR) {
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+ -1));
+ Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+
+ if (errorCodeObj) {
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+ Jim_ListAppendElement(interp, optListObj, errorCodeObj);
+ }
+ }
+ if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
+ ok = 0;
+ }
+ }
+ if (ok && handlerScriptObj) {
+
+ exitCode = Jim_EvalObj(interp, handlerScriptObj);
+ }
+
+ if (finallyScriptObj) {
+
+ Jim_Obj *prevResultObj = Jim_GetResult(interp);
+ Jim_IncrRefCount(prevResultObj);
+ int ret = Jim_EvalObj(interp, finallyScriptObj);
+ if (ret == JIM_OK) {
+ Jim_SetResult(interp, prevResultObj);
+ }
+ else {
+ exitCode = ret;
+ }
+ Jim_DecrRefCount(interp, prevResultObj);
+ }
+ if (!istry) {
+ Jim_SetResultInt(interp, exitCode);
+ exitCode = JIM_OK;
+ }
+ return exitCode;
+}
+
+
+static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimCatchTryHelper(interp, 0, argc, argv);
+}
+
+
+static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimCatchTryHelper(interp, 1, argc, argv);
+}
+
+
+
+static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
+ return JIM_ERR;
+ }
+
+ return Jim_RenameCommand(interp, argv[1], argv[2]);
+}
+
+#define JIM_DICTMATCH_KEYS 0x0001
+#define JIM_DICTMATCH_VALUES 0x002
+
+int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
+{
+ Jim_Obj *listObjPtr;
+ Jim_Dict *dict;
+ int i;
+
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ dict = objPtr->internalRep.dictValue;
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < dict->len; i += 2 ) {
+ Jim_Obj *keyObj = dict->table[i];
+ Jim_Obj *valObj = dict->table[i + 1];
+ if (patternObj) {
+ Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
+ if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {
+
+ continue;
+ }
+ }
+ if (return_types & JIM_DICTMATCH_KEYS) {
+ Jim_ListAppendElement(interp, listObjPtr, keyObj);
+ }
+ if (return_types & JIM_DICTMATCH_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, valObj);
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return -1;
+ }
+ return objPtr->internalRep.dictValue->len / 2;
+}
+
+Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
+ int i;
+
+ JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
+
+
+
+ for (i = 0; i < objc; i++) {
+ Jim_Obj **table;
+ int tablelen;
+ int j;
+
+ table = Jim_DictPairs(interp, objv[i], &tablelen);
+ if (tablelen && !table) {
+ Jim_FreeNewObj(interp, objPtr);
+ return NULL;
+ }
+ for (j = 0; j < tablelen; j += 2) {
+ DictAddElement(interp, objPtr, table[j], table[j + 1]);
+ }
+ }
+ return objPtr;
+}
+
+int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ char buffer[100];
+ Jim_Obj *output;
+ Jim_Dict *dict;
+
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ dict = objPtr->internalRep.dictValue;
+
+
+ snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
+ output = Jim_NewStringObj(interp, buffer, -1);
+ Jim_SetResult(interp, output);
+ return JIM_OK;
+}
+
+static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
+
+ Jim_AppendString(interp, prefixObj, " ", 1);
+ Jim_AppendString(interp, prefixObj, subcmd, -1);
+
+ return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
+}
+
+static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
+{
+ int i;
+ Jim_Obj *objPtr;
+ Jim_Obj *dictObj;
+ Jim_Obj **dictValues;
+ int len;
+ int ret = JIM_OK;
+
+
+ dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
+ if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ dictValues = Jim_DictPairs(interp, objPtr, &len);
+ if (len && dictValues == NULL) {
+ return JIM_ERR;
+ }
+ for (i = 0; i < len; i += 2) {
+ if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ }
+
+
+ if (Jim_Length(scriptObj)) {
+ ret = Jim_EvalObj(interp, scriptObj);
+
+
+ if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
+
+ Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
+ for (i = 0; i < keyc; i++) {
+ newkeyv[i] = keyv[i];
+ }
+
+ for (i = 0; i < len; i += 2) {
+
+ if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
+
+ objPtr = Jim_GetVariable(interp, dictValues[i], 0);
+ newkeyv[keyc] = dictValues[i];
+ Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
+ }
+ }
+ Jim_Free(newkeyv);
+ }
+ }
+
+ return ret;
+}
+
+
+static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int types = JIM_DICTMATCH_KEYS;
+
+ enum {
+ OPT_CREATE,
+ OPT_GET,
+ OPT_GETDEF,
+ OPT_GETWITHDEFAULT,
+ OPT_SET,
+ OPT_UNSET,
+ OPT_EXISTS,
+ OPT_KEYS,
+ OPT_SIZE,
+ OPT_INFO,
+ OPT_MERGE,
+ OPT_WITH,
+ OPT_APPEND,
+ OPT_LAPPEND,
+ OPT_INCR,
+ OPT_REMOVE,
+ OPT_VALUES,
+ OPT_FOR,
+ OPT_REPLACE,
+ OPT_UPDATE,
+ OPT_COUNT
+ };
+ static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+ JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
+ JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
+ JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
+ JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
+ JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
+ JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
+ JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
+ JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
+ JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
+ JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
+ JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
+ JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
+ JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
+ JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1),
+ JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
+ JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
+ JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
+ JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
+ JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
+ JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
+ { NULL }
+ };
+ const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+
+ switch (ct - cmds) {
+ case OPT_GET:
+ if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
+ JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_GETDEF:
+ case OPT_GETWITHDEFAULT:{
+ int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
+ if (rc == -1) {
+
+ return JIM_ERR;
+ }
+ if (rc == JIM_ERR) {
+ Jim_SetResult(interp, argv[argc - 1]);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+ }
+
+ case OPT_SET:
+ return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+
+ case OPT_EXISTS:{
+ int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
+ if (rc < 0) {
+ return JIM_ERR;
+ }
+ Jim_SetResultBool(interp, rc == JIM_OK);
+ return JIM_OK;
+ }
+
+ case OPT_UNSET:
+ if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+
+ case OPT_VALUES:
+ types = JIM_DICTMATCH_VALUES;
+
+ case OPT_KEYS:
+ return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
+
+ case OPT_SIZE:
+ if (Jim_DictSize(interp, argv[2]) < 0) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
+ return JIM_OK;
+
+ case OPT_MERGE:
+ if (argc == 2) {
+ return JIM_OK;
+ }
+ objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_CREATE:
+ objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_INFO:
+ return Jim_DictInfo(interp, argv[2]);
+
+ case OPT_WITH:
+ return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
+
+ case OPT_UPDATE:
+ if (argc < 6 || argc % 2) {
+
+ argc = 2;
+ }
+
+ default:
+ return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
+ }
+}
+
+
+static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-nobackslashes", "-nocommands", "-novariables", NULL
+ };
+ enum
+ { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
+ int i;
+ int flags = JIM_SUBST_FLAG;
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string");
+ return JIM_ERR;
+ }
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
+ JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_NOBACKSLASHES:
+ flags |= JIM_SUBST_NOESC;
+ break;
+ case OPT_NOCOMMANDS:
+ flags |= JIM_SUBST_NOCMD;
+ break;
+ case OPT_NOVARIABLES:
+ flags |= JIM_SUBST_NOVAR;
+ break;
+ }
+ }
+ if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+#ifdef jim_ext_namespace
+static int JimIsGlobalNamespace(Jim_Obj *objPtr)
+{
+ int len;
+ const char *str = Jim_GetString(objPtr, &len);
+ return len >= 2 && str[0] == ':' && str[1] == ':';
+}
+#endif
+
+
+static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int mode = 0;
+
+
+ enum {
+ INFO_ALIAS,
+ INFO_ARGS,
+ INFO_BODY,
+ INFO_CHANNELS,
+ INFO_COMMANDS,
+ INFO_COMPLETE,
+ INFO_EXISTS,
+ INFO_FRAME,
+ INFO_GLOBALS,
+ INFO_HOSTNAME,
+ INFO_LEVEL,
+ INFO_LOCALS,
+ INFO_NAMEOFEXECUTABLE,
+ INFO_PATCHLEVEL,
+ INFO_PROCS,
+ INFO_REFERENCES,
+ INFO_RETURNCODES,
+ INFO_SCRIPT,
+ INFO_SOURCE,
+ INFO_STACKTRACE,
+ INFO_STATICS,
+ INFO_VARS,
+ INFO_VERSION,
+ INFO_COUNT
+ };
+ static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
+ JIM_DEF_SUBCMD("alias", "command", 1, 1),
+ JIM_DEF_SUBCMD("args", "procname", 1, 1),
+ JIM_DEF_SUBCMD("body", "procname", 1, 1),
+ JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
+ JIM_DEF_SUBCMD("exists", "varName", 1, 1),
+ JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
+ JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
+ JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
+ JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
+ JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
+ JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("references", NULL, 0, 0),
+ JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
+ JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
+ JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
+ JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
+ JIM_DEF_SUBCMD("statics", "procname", 1, 1),
+ JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
+ JIM_DEF_SUBCMD("version", NULL, 0, 0),
+ { NULL }
+ };
+ const jim_subcmd_type *ct;
+#ifdef jim_ext_namespace
+ int nons = 0;
+
+ if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
+
+ argc--;
+ argv++;
+ nons = 1;
+ }
+#endif
+ ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+ if (!ct) {
+ return JIM_ERR;
+ }
+ if (ct->function) {
+
+ return ct->function(interp, argc, argv);
+ }
+
+ int option = ct - cmds;
+
+ switch (option) {
+ case INFO_EXISTS:
+ Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
+ return JIM_OK;
+
+ case INFO_ALIAS:{
+ Jim_Cmd *cmdPtr;
+
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
+ return JIM_OK;
+ }
+
+ case INFO_CHANNELS:
+ mode++;
+#ifndef jim_ext_aio
+ Jim_SetResultString(interp, "aio not enabled", -1);
+ return JIM_ERR;
+#endif
+
+ case INFO_PROCS:
+ mode++;
+
+ case INFO_COMMANDS:
+
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
+ return JIM_OK;
+
+ case INFO_VARS:
+ mode++;
+
+ case INFO_LOCALS:
+ mode++;
+
+ case INFO_GLOBALS:
+
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
+ return JIM_OK;
+
+ case INFO_SCRIPT:
+ if (argc == 3) {
+ Jim_IncrRefCount(argv[2]);
+ Jim_DecrRefCount(interp, interp->currentFilenameObj);
+ interp->currentFilenameObj = argv[2];
+ }
+ Jim_SetResult(interp, interp->currentFilenameObj);
+ return JIM_OK;
+
+ case INFO_SOURCE:{
+ Jim_Obj *resObjPtr;
+ Jim_Obj *fileNameObj;
+
+ if (argc == 4) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ return JIM_ERR;
+ }
+ if (argc == 5) {
+ jim_wide line;
+ if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
+ return JIM_ERR;
+ }
+ resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
+ Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
+ }
+ else {
+ int line;
+ fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
+ }
+ Jim_SetResult(interp, resObjPtr);
+ return JIM_OK;
+ }
+
+ case INFO_STACKTRACE:
+ Jim_SetResult(interp, interp->stackTrace);
+ return JIM_OK;
+
+ case INFO_LEVEL:
+ if (argc == 2) {
+ Jim_SetResultInt(interp, interp->framePtr->level);
+ }
+ else {
+ if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+
+ case INFO_FRAME:
+ if (argc == 2) {
+ Jim_SetResultInt(interp, interp->procLevel + 1);
+ }
+ else {
+ if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+
+ case INFO_BODY:
+ case INFO_STATICS:
+ case INFO_ARGS:{
+ Jim_Cmd *cmdPtr;
+
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (!cmdPtr->isproc) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
+ return JIM_ERR;
+ }
+ switch (option) {
+#ifdef JIM_NO_INTROSPECTION
+ default:
+ Jim_SetResultString(interp, "unsupported", -1);
+ return JIM_ERR;
+#else
+ case INFO_BODY:
+ Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
+ break;
+ case INFO_ARGS:
+ Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
+ break;
+#endif
+ case INFO_STATICS:
+ if (cmdPtr->u.proc.staticVars) {
+ Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
+ NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
+ }
+ break;
+ }
+ return JIM_OK;
+ }
+
+ case INFO_VERSION:
+ case INFO_PATCHLEVEL:{
+ char buf[(JIM_INTEGER_SPACE * 2) + 1];
+
+ sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetResultString(interp, buf, -1);
+ return JIM_OK;
+ }
+
+ case INFO_COMPLETE: {
+ char missing;
+
+ Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
+ if (missing != ' ' && argc == 4) {
+ Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
+ }
+ return JIM_OK;
+ }
+
+ case INFO_HOSTNAME:
+
+ return Jim_Eval(interp, "os.gethostname");
+
+ case INFO_NAMEOFEXECUTABLE:
+
+ return Jim_Eval(interp, "{info nameofexecutable}");
+
+ case INFO_RETURNCODES:
+ if (argc == 2) {
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; jimReturnCodes[i]; i++) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
+ jimReturnCodes[i], -1));
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ }
+ else if (argc == 3) {
+ long code;
+ const char *name;
+
+ if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
+ return JIM_ERR;
+ }
+ name = Jim_ReturnCode(code);
+ if (*name == '?') {
+ Jim_SetResultInt(interp, code);
+ }
+ else {
+ Jim_SetResultString(interp, name, -1);
+ }
+ }
+ return JIM_OK;
+ case INFO_REFERENCES:
+#ifdef JIM_REFERENCES
+ return JimInfoReferences(interp, argc, argv);
+#else
+ Jim_SetResultString(interp, "not supported", -1);
+ return JIM_ERR;
+#endif
+ default:
+ abort();
+ }
+}
+
+
+static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int result = 0;
+
+ static const char * const options[] = {
+ "-command", "-proc", "-alias", "-var", NULL
+ };
+ enum
+ {
+ OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
+ };
+ int option;
+
+ if (argc == 2) {
+ option = OPT_VAR;
+ objPtr = argv[1];
+ }
+ else if (argc == 3) {
+ if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = argv[2];
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?option? name");
+ return JIM_ERR;
+ }
+
+ if (option == OPT_VAR) {
+ result = Jim_GetVariable(interp, objPtr, 0) != NULL;
+ }
+ else {
+
+ Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
+
+ if (cmd) {
+ switch (option) {
+ case OPT_COMMAND:
+ result = 1;
+ break;
+
+ case OPT_ALIAS:
+ result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
+ break;
+
+ case OPT_PROC:
+ result = cmd->isproc;
+ break;
+ }
+ }
+ }
+ Jim_SetResultBool(interp, result);
+ return JIM_OK;
+}
+
+
+static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *str, *splitChars, *noMatchStart;
+ int splitLen, strLen;
+ Jim_Obj *resObjPtr;
+ int c;
+ int len;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(argv[1], &len);
+ if (len == 0) {
+ return JIM_OK;
+ }
+ strLen = Jim_Utf8Length(interp, argv[1]);
+
+
+ if (argc == 2) {
+ splitChars = " \n\t\r";
+ splitLen = 4;
+ }
+ else {
+ splitChars = Jim_String(argv[2]);
+ splitLen = Jim_Utf8Length(interp, argv[2]);
+ }
+
+ noMatchStart = str;
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (splitLen) {
+ Jim_Obj *objPtr;
+ while (strLen--) {
+ const char *sc = splitChars;
+ int scLen = splitLen;
+ int sl = utf8_tounicode(str, &c);
+ while (scLen--) {
+ int pc;
+ sc += utf8_tounicode(sc, &pc);
+ if (c == pc) {
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ noMatchStart = str + sl;
+ break;
+ }
+ }
+ str += sl;
+ }
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ }
+ else {
+ Jim_Obj **commonObj = NULL;
+#define NUM_COMMON (128 - 9)
+ while (strLen--) {
+ int n = utf8_tounicode(str, &c);
+#ifdef JIM_OPTIMIZATION
+ if (c >= 9 && c < 128) {
+
+ c -= 9;
+ if (!commonObj) {
+ commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
+ memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
+ }
+ if (!commonObj[c]) {
+ commonObj[c] = Jim_NewStringObj(interp, str, 1);
+ }
+ Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
+ str++;
+ continue;
+ }
+#endif
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
+ str += n;
+ }
+ Jim_Free(commonObj);
+ }
+
+ Jim_SetResult(interp, resObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *joinStr;
+ int joinStrLen;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ joinStr = " ";
+ joinStrLen = 1;
+ }
+ else {
+ joinStr = Jim_GetString(argv[2], &joinStrLen);
+ }
+ Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
+ return JIM_OK;
+}
+
+
+static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
+ return JIM_ERR;
+ }
+ objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listPtr, **outVec;
+ int outc, i;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
+ return JIM_ERR;
+ }
+ if (argv[2]->typePtr != &scanFmtStringObjType)
+ SetScanFmtFromAny(interp, argv[2]);
+ if (FormatGetError(argv[2]) != 0) {
+ Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
+ return JIM_ERR;
+ }
+ if (argc > 3) {
+ int maxPos = FormatGetMaxPos(argv[2]);
+ int count = FormatGetCnvCount(argv[2]);
+
+ if (maxPos > argc - 3) {
+ Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
+ return JIM_ERR;
+ }
+ else if (count > argc - 3) {
+ Jim_SetResultString(interp, "different numbers of variable names and "
+ "field specifiers", -1);
+ return JIM_ERR;
+ }
+ else if (count < argc - 3) {
+ Jim_SetResultString(interp, "variable is not assigned by any "
+ "conversion specifiers", -1);
+ return JIM_ERR;
+ }
+ }
+ listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
+ if (listPtr == 0)
+ return JIM_ERR;
+ if (argc > 3) {
+ int rc = JIM_OK;
+ int count = 0;
+
+ if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
+ int len = Jim_ListLength(interp, listPtr);
+
+ if (len != 0) {
+ JimListGetElements(interp, listPtr, &outc, &outVec);
+ for (i = 0; i < outc; ++i) {
+ if (Jim_Length(outVec[i]) > 0) {
+ ++count;
+ if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
+ rc = JIM_ERR;
+ }
+ }
+ }
+ }
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ else {
+ count = -1;
+ }
+ if (rc == JIM_OK) {
+ Jim_SetResultInt(interp, count);
+ }
+ return rc;
+ }
+ else {
+ if (listPtr == (Jim_Obj *)EOF) {
+ Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
+ return JIM_OK;
+ }
+ Jim_SetResult(interp, listPtr);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, argv[1]);
+ if (argc == 3) {
+ JimSetStackTrace(interp, argv[2]);
+ return JIM_ERR;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc != 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last");
+ return JIM_ERR;
+ }
+ if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ jim_wide count;
+
+ if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
+ return JIM_ERR;
+ }
+ if (count == 0 || argc == 2) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+
+ argc -= 2;
+ argv += 2;
+
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(objPtr, argc * count);
+ while (count--) {
+ ListInsertElements(objPtr, -1, argc, argv);
+ }
+
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+char **Jim_GetEnviron(void)
+{
+#if defined(HAVE__NSGETENVIRON)
+ return *_NSGetEnviron();
+#elif defined(_environ)
+ return _environ;
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+ return environ;
+#endif
+}
+
+void Jim_SetEnviron(char **env)
+{
+#if defined(HAVE__NSGETENVIRON)
+ *_NSGetEnviron() = env;
+#elif defined(_environ)
+ _environ = env;
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+
+ environ = env;
+#endif
+}
+
+
+static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *key;
+ const char *val;
+
+ if (argc == 1) {
+ char **e = Jim_GetEnviron();
+
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; e[i]; i++) {
+ const char *equals = strchr(e[i], '=');
+
+ if (equals) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
+ equals - e[i]));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+ }
+
+ if (argc > 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
+ return JIM_ERR;
+ }
+ key = Jim_String(argv[1]);
+ val = getenv(key);
+ if (val == NULL) {
+ if (argc < 3) {
+ Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
+ return JIM_ERR;
+ }
+ val = Jim_String(argv[2]);
+ }
+ Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
+ return JIM_OK;
+}
+
+
+static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "fileName");
+ return JIM_ERR;
+ }
+ retval = Jim_EvalFile(interp, Jim_String(argv[1]));
+ if (retval == JIM_RETURN)
+ return JIM_OK;
+ return retval;
+}
+
+
+static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *revObjPtr, **ele;
+ int len;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ JimListGetElements(interp, argv[1], &len, &ele);
+ revObjPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(revObjPtr, len);
+ len--;
+ while (len >= 0)
+ ListAppendElement(revObjPtr, ele[len--]);
+ Jim_SetResult(interp, revObjPtr);
+ return JIM_OK;
+}
+
+static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
+{
+ jim_wide len;
+
+ if (step == 0)
+ return -1;
+ if (start == end)
+ return 0;
+ else if (step > 0 && start > end)
+ return -1;
+ else if (step < 0 && end > start)
+ return -1;
+ len = end - start;
+ if (len < 0)
+ len = -len;
+ if (step < 0)
+ step = -step;
+ len = 1 + ((len - 1) / step);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ return (int)((len < 0) ? -1 : len);
+}
+
+
+static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide start = 0, end, step = 1;
+ int len, i;
+ Jim_Obj *objPtr;
+
+ if (argc < 2 || argc > 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
+ return JIM_ERR;
+ }
+ else {
+ if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
+ Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
+ return JIM_ERR;
+ if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
+ return JIM_ERR;
+ }
+ if ((len = JimRangeLen(start, end, step)) == -1) {
+ Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+ ListEnsureLength(objPtr, len);
+ for (i = 0; i < len; i++)
+ ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide min = 0, max = 0, len, maxMul;
+
+ if (argc < 1 || argc > 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?min? max");
+ return JIM_ERR;
+ }
+ if (argc == 1) {
+ max = JIM_WIDE_MAX;
+ } else if (argc == 2) {
+ if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
+ return JIM_ERR;
+ } else if (argc == 3) {
+ if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
+ Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
+ return JIM_ERR;
+ }
+ len = max-min;
+ if (len < 0) {
+ Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
+ return JIM_ERR;
+ }
+ maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
+ while (1) {
+ jim_wide r;
+
+ JimRandomBytes(interp, &r, sizeof(jim_wide));
+ if (r < 0 || r >= maxMul) continue;
+ r = (len == 0) ? 0 : r%len;
+ Jim_SetResultInt(interp, min+r);
+ return JIM_OK;
+ }
+}
+
+static const struct {
+ const char *name;
+ Jim_CmdProc *cmdProc;
+} Jim_CoreCommandsTable[] = {
+ {"alias", Jim_AliasCoreCommand},
+ {"set", Jim_SetCoreCommand},
+ {"unset", Jim_UnsetCoreCommand},
+ {"puts", Jim_PutsCoreCommand},
+ {"+", Jim_AddCoreCommand},
+ {"*", Jim_MulCoreCommand},
+ {"-", Jim_SubCoreCommand},
+ {"/", Jim_DivCoreCommand},
+ {"incr", Jim_IncrCoreCommand},
+ {"while", Jim_WhileCoreCommand},
+ {"loop", Jim_LoopCoreCommand},
+ {"for", Jim_ForCoreCommand},
+ {"foreach", Jim_ForeachCoreCommand},
+ {"lmap", Jim_LmapCoreCommand},
+ {"lassign", Jim_LassignCoreCommand},
+ {"if", Jim_IfCoreCommand},
+ {"switch", Jim_SwitchCoreCommand},
+ {"list", Jim_ListCoreCommand},
+ {"lindex", Jim_LindexCoreCommand},
+ {"lset", Jim_LsetCoreCommand},
+ {"lsearch", Jim_LsearchCoreCommand},
+ {"llength", Jim_LlengthCoreCommand},
+ {"lappend", Jim_LappendCoreCommand},
+ {"linsert", Jim_LinsertCoreCommand},
+ {"lreplace", Jim_LreplaceCoreCommand},
+ {"lsort", Jim_LsortCoreCommand},
+ {"append", Jim_AppendCoreCommand},
+ {"eval", Jim_EvalCoreCommand},
+ {"uplevel", Jim_UplevelCoreCommand},
+ {"expr", Jim_ExprCoreCommand},
+ {"break", Jim_BreakCoreCommand},
+ {"continue", Jim_ContinueCoreCommand},
+ {"proc", Jim_ProcCoreCommand},
+ {"xtrace", Jim_XtraceCoreCommand},
+ {"concat", Jim_ConcatCoreCommand},
+ {"return", Jim_ReturnCoreCommand},
+ {"upvar", Jim_UpvarCoreCommand},
+ {"global", Jim_GlobalCoreCommand},
+ {"string", Jim_StringCoreCommand},
+ {"time", Jim_TimeCoreCommand},
+ {"timerate", Jim_TimeRateCoreCommand},
+ {"exit", Jim_ExitCoreCommand},
+ {"catch", Jim_CatchCoreCommand},
+ {"try", Jim_TryCoreCommand},
+#ifdef JIM_REFERENCES
+ {"ref", Jim_RefCoreCommand},
+ {"getref", Jim_GetrefCoreCommand},
+ {"setref", Jim_SetrefCoreCommand},
+ {"finalize", Jim_FinalizeCoreCommand},
+ {"collect", Jim_CollectCoreCommand},
+#endif
+ {"rename", Jim_RenameCoreCommand},
+ {"dict", Jim_DictCoreCommand},
+ {"subst", Jim_SubstCoreCommand},
+ {"info", Jim_InfoCoreCommand},
+ {"exists", Jim_ExistsCoreCommand},
+ {"split", Jim_SplitCoreCommand},
+ {"join", Jim_JoinCoreCommand},
+ {"format", Jim_FormatCoreCommand},
+ {"scan", Jim_ScanCoreCommand},
+ {"error", Jim_ErrorCoreCommand},
+ {"lrange", Jim_LrangeCoreCommand},
+ {"lrepeat", Jim_LrepeatCoreCommand},
+ {"env", Jim_EnvCoreCommand},
+ {"source", Jim_SourceCoreCommand},
+ {"lreverse", Jim_LreverseCoreCommand},
+ {"range", Jim_RangeCoreCommand},
+ {"rand", Jim_RandCoreCommand},
+ {"tailcall", Jim_TailcallCoreCommand},
+ {"local", Jim_LocalCoreCommand},
+ {"upcall", Jim_UpcallCoreCommand},
+ {"apply", Jim_ApplyCoreCommand},
+ {"stacktrace", Jim_StacktraceCoreCommand},
+ {NULL, NULL},
+};
+
+void Jim_RegisterCoreCommands(Jim_Interp *interp)
+{
+ int i = 0;
+
+ while (Jim_CoreCommandsTable[i].name != NULL) {
+ Jim_CreateCommand(interp,
+ Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
+ i++;
+ }
+}
+
+void Jim_MakeErrorMessage(Jim_Interp *interp)
+{
+ Jim_Obj *argv[2];
+
+ argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
+ argv[1] = interp->result;
+
+ Jim_EvalObjVector(interp, 2, argv);
+}
+
+static char **JimSortStringTable(const char *const *tablePtr)
+{
+ int count;
+ char **tablePtrSorted;
+
+
+ for (count = 0; tablePtr[count]; count++) {
+ }
+
+
+ tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
+ memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
+ qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
+ tablePtrSorted[count] = NULL;
+
+ return tablePtrSorted;
+}
+
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name)
+{
+ char **tablePtrSorted;
+ int i;
+
+ if (name == NULL) {
+ name = "option";
+ }
+
+ Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
+ tablePtrSorted = JimSortStringTable(tablePtr);
+ for (i = 0; tablePtrSorted[i]; i++) {
+ if (tablePtrSorted[i + 1] == NULL && i > 0) {
+ Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
+ if (tablePtrSorted[i + 1]) {
+ Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+ }
+ }
+ Jim_Free(tablePtrSorted);
+}
+
+
+int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
+{
+ if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
+ int i;
+ char **tablePtrSorted = JimSortStringTable(tablePtr);
+ Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+ for (i = 0; tablePtrSorted[i]; i++) {
+ Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
+ }
+ Jim_Free(tablePtrSorted);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+static const Jim_ObjType getEnumObjType = {
+ "get-enum",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES
+};
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *const *tablePtr, int *indexPtr, const char *name, int flags)
+{
+ const char *bad = "bad ";
+ const char *const *entryPtr = NULL;
+ int i;
+ int match = -1;
+ int arglen;
+ const char *arg;
+
+ if (objPtr->typePtr == &getEnumObjType) {
+ if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
+ *indexPtr = objPtr->internalRep.ptrIntValue.int2;
+ return JIM_OK;
+ }
+ }
+
+ arg = Jim_GetString(objPtr, &arglen);
+
+ *indexPtr = -1;
+
+ for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
+ if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
+
+ match = i;
+ goto found;
+ }
+ if (flags & JIM_ENUM_ABBREV) {
+ if (strncmp(arg, *entryPtr, arglen) == 0) {
+ if (*arg == '-' && arglen == 1) {
+ break;
+ }
+ if (match >= 0) {
+ bad = "ambiguous ";
+ goto ambiguous;
+ }
+ match = i;
+ }
+ }
+ }
+
+
+ if (match >= 0) {
+ found:
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &getEnumObjType;
+ objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
+ objPtr->internalRep.ptrIntValue.int1 = flags;
+ objPtr->internalRep.ptrIntValue.int2 = match;
+
+ *indexPtr = match;
+ return JIM_OK;
+ }
+
+ ambiguous:
+ if (flags & JIM_ERRMSG) {
+ JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
+ }
+ return JIM_ERR;
+}
+
+int Jim_FindByName(const char *name, const char * const array[], size_t len)
+{
+ int i;
+
+ for (i = 0; i < (int)len; i++) {
+ if (array[i] && strcmp(array[i], name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int Jim_IsDict(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &dictObjType;
+}
+
+int Jim_IsList(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &listObjType;
+}
+
+void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
+{
+
+ int len = strlen(format);
+ int extra = 0;
+ int n = 0;
+ const char *params[5];
+ int nobjparam = 0;
+ Jim_Obj *objparam[5];
+ char *buf;
+ va_list args;
+ int i;
+
+ va_start(args, format);
+
+ for (i = 0; i < len && n < 5; i++) {
+ int l;
+
+ if (strncmp(format + i, "%s", 2) == 0) {
+ params[n] = va_arg(args, char *);
+
+ l = strlen(params[n]);
+ }
+ else if (strncmp(format + i, "%#s", 3) == 0) {
+ Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
+
+ params[n] = Jim_GetString(objPtr, &l);
+ objparam[nobjparam++] = objPtr;
+ Jim_IncrRefCount(objPtr);
+ }
+ else {
+ if (format[i] == '%') {
+ i++;
+ }
+ continue;
+ }
+ n++;
+ extra += l;
+ }
+
+ len += extra;
+ buf = Jim_Alloc(len + 1);
+ len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
+
+ va_end(args);
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+
+ for (i = 0; i < nobjparam; i++) {
+ Jim_DecrRefCount(interp, objparam[i]);
+ }
+}
+
+int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
+{
+ if (abi_version != JIM_ABI_VERSION) {
+ Jim_SetResultString(interp, "ABI version mismatch", -1);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+#ifndef jim_ext_package
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+ return JIM_OK;
+}
+#endif
+#ifndef jim_ext_aio
+int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+{
+ return -1;
+}
+#endif
+
+
+#include
+#include
+
+
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ return JIM_OK;
+}
+
+static const jim_subcmd_type dummy_subcmd = {
+ "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
+};
+
+static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+{
+
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_Obj *sortCmd[2];
+
+ for (; ct->cmd; ct++) {
+ if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
+ }
+ }
+
+
+ sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
+ sortCmd[1] = listObj;
+
+ if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
+ return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
+ }
+
+ return Jim_GetResult(interp);
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
+ Jim_Obj *cmd, Jim_Obj *subcmd)
+{
+ Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
+ subcmd, subcmd_cmd_list(interp, command_table, ", "));
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+ Jim_Obj *const *argv)
+{
+ Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
+ argv[0], subcmd_cmd_list(interp, command_table, ", "));
+}
+
+static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
+{
+ if (cmd) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
+ if (ct->args && *ct->args) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+ }
+}
+
+void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
+{
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+ add_cmd_usage(interp, ct, subcmd);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+}
+
+static const Jim_ObjType subcmdLookupObjType = {
+ "subcmd-lookup",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES
+};
+
+const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
+ int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct;
+ const jim_subcmd_type *partial = 0;
+ int cmdlen;
+ Jim_Obj *cmd;
+ const char *cmdstr;
+ int help = 0;
+ int argsok = 1;
+
+ if (argc < 2) {
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
+ "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
+ return 0;
+ }
+
+ cmd = argv[1];
+
+
+ if (cmd->typePtr == &subcmdLookupObjType) {
+ if (cmd->internalRep.ptrIntValue.ptr == command_table) {
+ ct = command_table + cmd->internalRep.ptrIntValue.int1;
+ goto found;
+ }
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+ if (argc == 2) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ help = 1;
+
+
+ cmd = argv[2];
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+ Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
+ return &dummy_subcmd;
+ }
+
+ cmdstr = Jim_GetString(cmd, &cmdlen);
+
+ for (ct = command_table; ct->cmd; ct++) {
+ if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+
+ break;
+ }
+ if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+ if (partial) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
+ return 0;
+ }
+ partial = ct;
+ }
+ continue;
+ }
+
+
+ if (partial && !ct->cmd) {
+ ct = partial;
+ }
+
+ if (!ct->cmd) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
+ return 0;
+ }
+
+ if (help) {
+ Jim_SetResultString(interp, "Usage: ", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ return &dummy_subcmd;
+ }
+
+
+ Jim_FreeIntRep(interp, cmd);
+ cmd->typePtr = &subcmdLookupObjType;
+ cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
+ cmd->internalRep.ptrIntValue.int1 = ct - command_table;
+
+found:
+
+
+ if (argc - 2 < ct->minargs) {
+ argsok = 0;
+ }
+ else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
+ argsok = 0;
+ }
+ else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
+
+ argsok = 0;
+ }
+ if (!argsok) {
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+ return 0;
+ }
+
+
+ return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
+{
+ int ret = JIM_ERR;
+
+ if (ct) {
+ if (ct->flags & JIM_MODFLAG_FULLARGV) {
+ ret = ct->function(interp, argc, argv);
+ }
+ else {
+ ret = ct->function(interp, argc - 2, argv + 2);
+ }
+ if (ret < 0) {
+ Jim_SubCmdArgError(interp, ct, argv[0]);
+ ret = JIM_ERR;
+ }
+ }
+ return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct =
+ Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+ return Jim_CallSubCmd(interp, ct, argc, argv);
+}
+
+#include
+#include
+#include
+#include
+#include
+
+
+int utf8_fromunicode(char *p, unsigned uc)
+{
+ if (uc <= 0x7f) {
+ *p = uc;
+ return 1;
+ }
+ else if (uc <= 0x7ff) {
+ *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 2;
+ }
+ else if (uc <= 0xffff) {
+ *p++ = 0xe0 | ((uc & 0xf000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 3;
+ }
+
+ else {
+ *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
+ *p++ = 0x80 | ((uc & 0x3f000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 4;
+ }
+}
+
+#include
+#include
+#include
+
+
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+ const char *span, *format, *formatEnd, *msg;
+ int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+ static const char * const mixedXPG =
+ "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ static const char * const badIndex[2] = {
+ "not enough arguments for all format specifiers",
+ "\"%n$\" argument index out of range"
+ };
+ int formatLen;
+ Jim_Obj *resultPtr;
+
+ char *num_buffer = NULL;
+ int num_buffer_size = 0;
+
+ span = format = Jim_GetString(fmtObjPtr, &formatLen);
+ formatEnd = format + formatLen;
+ resultPtr = Jim_NewEmptyStringObj(interp);
+
+ while (format != formatEnd) {
+ char *end;
+ int gotMinus, sawFlag;
+ int gotPrecision, useShort;
+ long width, precision;
+ int newXpg;
+ int ch;
+ int step;
+ int doubleType;
+ char pad = ' ';
+ char spec[2*JIM_INTEGER_SPACE + 12];
+ char *p;
+
+ int formatted_chars;
+ int formatted_bytes;
+ const char *formatted_buf;
+
+ step = utf8_tounicode(format, &ch);
+ format += step;
+ if (ch != '%') {
+ numBytes += step;
+ continue;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ numBytes = 0;
+ }
+
+
+ step = utf8_tounicode(format, &ch);
+ if (ch == '%') {
+ span = format;
+ numBytes = step;
+ format += step;
+ continue;
+ }
+
+
+ newXpg = 0;
+ if (isdigit(ch)) {
+ int position = strtoul(format, &end, 10);
+ if (*end == '$') {
+ newXpg = 1;
+ objIndex = position - 1;
+ format = end + 1;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+ if (newXpg) {
+ if (gotSequential) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotXpg = 1;
+ } else {
+ if (gotXpg) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotSequential = 1;
+ }
+ if ((objIndex < 0) || (objIndex >= objc)) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+
+ p = spec;
+ *p++ = '%';
+
+ gotMinus = 0;
+ sawFlag = 1;
+ do {
+ switch (ch) {
+ case '-':
+ gotMinus = 1;
+ break;
+ case '0':
+ pad = ch;
+ break;
+ case ' ':
+ case '+':
+ case '#':
+ break;
+ default:
+ sawFlag = 0;
+ continue;
+ }
+ *p++ = ch;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+
+ } while (sawFlag && (p - spec <= 5));
+
+
+ width = 0;
+ if (isdigit(ch)) {
+ width = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+ goto error;
+ }
+ if (width < 0) {
+ width = -width;
+ if (!gotMinus) {
+ *p++ = '-';
+ gotMinus = 1;
+ }
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ gotPrecision = precision = 0;
+ if (ch == '.') {
+ gotPrecision = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ if (isdigit(ch)) {
+ precision = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+ goto error;
+ }
+
+
+ if (precision < 0) {
+ precision = 0;
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ useShort = 0;
+ if (ch == 'h') {
+ useShort = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == 'l') {
+
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ if (ch == 'l') {
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+
+ format += step;
+ span = format;
+
+
+ if (ch == 'i') {
+ ch = 'd';
+ }
+
+ doubleType = 0;
+
+ switch (ch) {
+ case '\0':
+ msg = "format string ended in middle of field specifier";
+ goto errorMsg;
+ case 's': {
+ formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+ formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+ if (gotPrecision && (precision < formatted_chars)) {
+
+ formatted_chars = precision;
+ formatted_bytes = utf8_index(formatted_buf, precision);
+ }
+ break;
+ }
+ case 'c': {
+ jim_wide code;
+
+ if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+ goto error;
+ }
+
+ formatted_bytes = utf8_getchars(spec, code);
+ formatted_buf = spec;
+ formatted_chars = 1;
+ break;
+ }
+ case 'b': {
+ unsigned jim_wide w;
+ int length;
+ int i;
+ int j;
+
+ if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
+ goto error;
+ }
+ length = sizeof(w) * 8;
+
+
+
+ if (num_buffer_size < length + 1) {
+ num_buffer_size = length + 1;
+ num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+ }
+
+ j = 0;
+ for (i = length; i > 0; ) {
+ i--;
+ if (w & ((unsigned jim_wide)1 << i)) {
+ num_buffer[j++] = '1';
+ }
+ else if (j || i == 0) {
+ num_buffer[j++] = '0';
+ }
+ }
+ num_buffer[j] = 0;
+ formatted_chars = formatted_bytes = j;
+ formatted_buf = num_buffer;
+ break;
+ }
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ doubleType = 1;
+
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X': {
+ jim_wide w;
+ double d;
+ int length;
+
+
+ if (width) {
+ p += sprintf(p, "%ld", width);
+ }
+ if (gotPrecision) {
+ p += sprintf(p, ".%ld", precision);
+ }
+
+
+ if (doubleType) {
+ if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+ goto error;
+ }
+ length = MAX_FLOAT_WIDTH;
+ }
+ else {
+ if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+ goto error;
+ }
+ length = JIM_INTEGER_SPACE;
+ if (useShort) {
+ if (ch == 'd') {
+ w = (short)w;
+ }
+ else {
+ w = (unsigned short)w;
+ }
+ }
+ *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+ if (sizeof(long long) == sizeof(jim_wide)) {
+ *p++ = 'l';
+ }
+#endif
+ }
+
+ *p++ = (char) ch;
+ *p = '\0';
+
+
+ if (width > 10000 || length > 10000 || precision > 10000) {
+ Jim_SetResultString(interp, "format too long", -1);
+ goto error;
+ }
+
+
+
+ if (width > length) {
+ length = width;
+ }
+ if (gotPrecision) {
+ length += precision;
+ }
+
+
+ if (num_buffer_size < length + 1) {
+ num_buffer_size = length + 1;
+ num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+ }
+
+ if (doubleType) {
+ snprintf(num_buffer, length + 1, spec, d);
+ }
+ else {
+ formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+ }
+ formatted_chars = formatted_bytes = strlen(num_buffer);
+ formatted_buf = num_buffer;
+ break;
+ }
+
+ default: {
+
+ spec[0] = ch;
+ spec[1] = '\0';
+ Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+ goto error;
+ }
+ }
+
+ if (!gotMinus) {
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+ }
+
+ Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+
+ objIndex += gotSequential;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ }
+
+ Jim_Free(num_buffer);
+ return resultPtr;
+
+ errorMsg:
+ Jim_SetResultString(interp, msg, -1);
+ error:
+ Jim_FreeNewObj(interp, resultPtr);
+ Jim_Free(num_buffer);
+ return NULL;
+}
+
+
+#if defined(JIM_REGEXP)
+#include
+#include
+#include
+#include
+
+
+
+#define REG_MAX_PAREN 100
+
+
+
+#define END 0
+#define BOL 1
+#define EOL 2
+#define ANY 3
+#define ANYOF 4
+#define ANYBUT 5
+#define BRANCH 6
+#define BACK 7
+#define EXACTLY 8
+#define NOTHING 9
+#define REP 10
+#define REPMIN 11
+#define REPX 12
+#define REPXMIN 13
+#define BOLX 14
+#define EOLX 15
+#define WORDA 16
+#define WORDZ 17
+
+#define OPENNC 1000
+#define OPEN 1001
+
+
+
+
+#define CLOSENC 2000
+#define CLOSE 2001
+#define CLOSE_END (CLOSE+REG_MAX_PAREN)
+
+#define REG_MAGIC 0xFADED00D
+
+
+#define OP(preg, p) (preg->program[p])
+#define NEXT(preg, p) (preg->program[p + 1])
+#define OPERAND(p) ((p) + 2)
+
+
+
+
+#define FAIL(R,M) { (R)->err = (M); return (M); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define META "^$.[()|?{+*"
+
+#define HASWIDTH 1
+#define SIMPLE 2
+#define SPSTART 4
+#define WORST 0
+
+#define MAX_REP_COUNT 1000000
+
+static int reg(regex_t *preg, int paren, int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail(regex_t *preg, int p, int val);
+static void regoptail(regex_t *preg, int p, int val );
+static int regopsize(regex_t *preg, int p );
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+
+#ifdef DEBUG
+static int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+static int str_int_len(const int *seq)
+{
+ int n = 0;
+ while (*seq++) {
+ n++;
+ }
+ return n;
+}
+
+int jim_regcomp(regex_t *preg, const char *exp, int cflags)
+{
+ int scan;
+ int longest;
+ unsigned len;
+ int flags;
+
+#ifdef DEBUG
+ fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+ memset(preg, 0, sizeof(*preg));
+
+ if (exp == NULL)
+ FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+
+ preg->cflags = cflags;
+ preg->regparse = exp;
+
+
+ preg->proglen = (strlen(exp) + 1) * 5;
+ preg->program = malloc(preg->proglen * sizeof(int));
+ if (preg->program == NULL)
+ FAIL(preg, REG_ERR_NOMEM);
+
+ regc(preg, REG_MAGIC);
+ if (reg(preg, 0, &flags) == 0) {
+ return preg->err;
+ }
+
+
+ if (preg->re_nsub >= REG_MAX_PAREN)
+ FAIL(preg,REG_ERR_TOO_BIG);
+
+
+ preg->regstart = 0;
+ preg->reganch = 0;
+ preg->regmust = 0;
+ preg->regmlen = 0;
+ scan = 1;
+ if (OP(preg, regnext(preg, scan)) == END) {
+ scan = OPERAND(scan);
+
+
+ if (OP(preg, scan) == EXACTLY) {
+ preg->regstart = preg->program[OPERAND(scan)];
+ }
+ else if (OP(preg, scan) == BOL)
+ preg->reganch++;
+
+ if (flags&SPSTART) {
+ longest = 0;
+ len = 0;
+ for (; scan != 0; scan = regnext(preg, scan)) {
+ if (OP(preg, scan) == EXACTLY) {
+ int plen = str_int_len(preg->program + OPERAND(scan));
+ if (plen >= len) {
+ longest = OPERAND(scan);
+ len = plen;
+ }
+ }
+ }
+ preg->regmust = longest;
+ preg->regmlen = len;
+ }
+ }
+
+#ifdef DEBUG
+ regdump(preg);
+#endif
+
+ return 0;
+}
+
+static int reg(regex_t *preg, int paren, int *flagp )
+{
+ int ret;
+ int br;
+ int ender;
+ int parno = 0;
+ int flags;
+
+ *flagp = HASWIDTH;
+
+
+ if (paren) {
+ if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
+
+ preg->regparse += 2;
+ parno = -1;
+ }
+ else {
+ parno = ++preg->re_nsub;
+ }
+ ret = regnode(preg, OPEN+parno);
+ } else
+ ret = 0;
+
+
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ if (ret != 0)
+ regtail(preg, ret, br);
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*preg->regparse == '|') {
+ preg->regparse++;
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ regtail(preg, ret, br);
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+
+ ender = regnode(preg, (paren) ? CLOSE+parno : END);
+ regtail(preg, ret, ender);
+
+
+ for (br = ret; br != 0; br = regnext(preg, br))
+ regoptail(preg, br, ender);
+
+
+ if (paren && *preg->regparse++ != ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else if (!paren && *preg->regparse != '\0') {
+ if (*preg->regparse == ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else {
+ preg->err = REG_ERR_JUNK_ON_END;
+ return 0;
+ }
+ }
+
+ return(ret);
+}
+
+static int regbranch(regex_t *preg, int *flagp )
+{
+ int ret;
+ int chain;
+ int latest;
+ int flags;
+
+ *flagp = WORST;
+
+ ret = regnode(preg, BRANCH);
+ chain = 0;
+ while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+ *preg->regparse != '|') {
+ latest = regpiece(preg, &flags);
+ if (latest == 0)
+ return 0;
+ *flagp |= flags&HASWIDTH;
+ if (chain == 0) {
+ *flagp |= flags&SPSTART;
+ }
+ else {
+ regtail(preg, chain, latest);
+ }
+ chain = latest;
+ }
+ if (chain == 0)
+ (void) regnode(preg, NOTHING);
+
+ return(ret);
+}
+
+static int regpiece(regex_t *preg, int *flagp)
+{
+ int ret;
+ char op;
+ int next;
+ int flags;
+ int min;
+ int max;
+
+ ret = regatom(preg, &flags);
+ if (ret == 0)
+ return 0;
+
+ op = *preg->regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?') {
+ preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+ return 0;
+ }
+
+
+ if (op == '{') {
+ char *end;
+
+ min = strtoul(preg->regparse + 1, &end, 10);
+ if (end == preg->regparse + 1) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (*end == '}') {
+ max = min;
+ }
+ else if (*end == '\0') {
+ preg->err = REG_ERR_UNMATCHED_BRACES;
+ return 0;
+ }
+ else {
+ preg->regparse = end;
+ max = strtoul(preg->regparse + 1, &end, 10);
+ if (*end != '}') {
+ preg->err = REG_ERR_UNMATCHED_BRACES;
+ return 0;
+ }
+ }
+ if (end == preg->regparse + 1) {
+ max = MAX_REP_COUNT;
+ }
+ else if (max < min || max >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (min >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+
+ preg->regparse = strchr(preg->regparse, '}');
+ }
+ else {
+ min = (op == '+');
+ max = (op == '?' ? 1 : MAX_REP_COUNT);
+ }
+
+ if (preg->regparse[1] == '?') {
+ preg->regparse++;
+ next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+ }
+ else {
+ next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+ }
+ preg->program[ret + 2] = max;
+ preg->program[ret + 3] = min;
+ preg->program[ret + 4] = 0;
+
+ *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+ if (!(flags & SIMPLE)) {
+ int back = regnode(preg, BACK);
+ regtail(preg, back, ret);
+ regtail(preg, next, back);
+ }
+
+ preg->regparse++;
+ if (ISMULT(*preg->regparse)) {
+ preg->err = REG_ERR_NESTED_COUNT;
+ return 0;
+ }
+
+ return ret;
+}
+
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+ if (lower > upper) {
+ reg_addrange(preg, upper, lower);
+ }
+
+ regc(preg, upper - lower + 1);
+ regc(preg, lower);
+}
+
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+ while (*str) {
+ reg_addrange(preg, *str, *str);
+ str++;
+ }
+}
+
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+static int hexdigitval(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int parse_hex(const char *s, int n, int *uc)
+{
+ int val = 0;
+ int k;
+
+ for (k = 0; k < n; k++) {
+ int c = hexdigitval(*s++);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+ if (k) {
+ *uc = val;
+ }
+ return k;
+}
+
+static int reg_decode_escape(const char *s, int *ch)
+{
+ int n;
+ const char *s0 = s;
+
+ *ch = *s++;
+
+ switch (*ch) {
+ case 'b': *ch = '\b'; break;
+ case 'e': *ch = 27; break;
+ case 'f': *ch = '\f'; break;
+ case 'n': *ch = '\n'; break;
+ case 'r': *ch = '\r'; break;
+ case 't': *ch = '\t'; break;
+ case 'v': *ch = '\v'; break;
+ case 'u':
+ if (*s == '{') {
+
+ n = parse_hex(s + 1, 6, ch);
+ if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
+ s += n + 2;
+ }
+ else {
+
+ *ch = 'u';
+ }
+ }
+ else if ((n = parse_hex(s, 4, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case 'U':
+ if ((n = parse_hex(s, 8, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case 'x':
+ if ((n = parse_hex(s, 2, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case '\0':
+ s--;
+ *ch = '\\';
+ break;
+ }
+ return s - s0;
+}
+
+static int regatom(regex_t *preg, int *flagp)
+{
+ int ret;
+ int flags;
+ int nocase = (preg->cflags & REG_ICASE);
+
+ int ch;
+ int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+ *flagp = WORST;
+
+ preg->regparse += n;
+ switch (ch) {
+
+ case '^':
+ ret = regnode(preg, BOL);
+ break;
+ case '$':
+ ret = regnode(preg, EOL);
+ break;
+ case '.':
+ ret = regnode(preg, ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ const char *pattern = preg->regparse;
+
+ if (*pattern == '^') {
+ ret = regnode(preg, ANYBUT);
+ pattern++;
+ } else
+ ret = regnode(preg, ANYOF);
+
+
+ if (*pattern == ']' || *pattern == '-') {
+ reg_addrange(preg, *pattern, *pattern);
+ pattern++;
+ }
+
+ while (*pattern != ']') {
+
+ int start;
+ int end;
+
+ enum {
+ CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
+ CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
+ CC_NUM
+ };
+ int cc;
+
+ if (!*pattern) {
+ preg->err = REG_ERR_UNMATCHED_BRACKET;
+ return 0;
+ }
+
+ pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+ if (start == '\\') {
+
+ switch (*pattern) {
+ case 's':
+ pattern++;
+ cc = CC_SPACE;
+ goto cc_switch;
+ case 'd':
+ pattern++;
+ cc = CC_DIGIT;
+ goto cc_switch;
+ case 'w':
+ pattern++;
+ reg_addrange(preg, '_', '_');
+ cc = CC_ALNUM;
+ goto cc_switch;
+ }
+ pattern += reg_decode_escape(pattern, &start);
+ if (start == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ if (start == '\\' && *pattern == 0) {
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ }
+ }
+ if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
+
+ pattern += utf8_tounicode(pattern, &end);
+ pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+ if (end == '\\') {
+ pattern += reg_decode_escape(pattern, &end);
+ if (end == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ if (end == '\\' && *pattern == 0) {
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ }
+ }
+
+ reg_addrange(preg, start, end);
+ continue;
+ }
+ if (start == '[' && pattern[0] == ':') {
+ static const char *character_class[] = {
+ ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
+ ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
+ };
+
+ for (cc = 0; cc < CC_NUM; cc++) {
+ n = strlen(character_class[cc]);
+ if (strncmp(pattern, character_class[cc], n) == 0) {
+ if (pattern[n] != ']') {
+ preg->err = REG_ERR_UNMATCHED_BRACKET;
+ return 0;
+ }
+
+ pattern += n + 1;
+ break;
+ }
+ }
+ if (cc != CC_NUM) {
+cc_switch:
+ switch (cc) {
+ case CC_ALNUM:
+ reg_addrange(preg, '0', '9');
+
+ case CC_ALPHA:
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ break;
+ case CC_SPACE:
+ reg_addrange_str(preg, " \t\r\n\f\v");
+ break;
+ case CC_BLANK:
+ reg_addrange_str(preg, " \t");
+ break;
+ case CC_UPPER:
+ reg_addrange(preg, 'A', 'Z');
+ break;
+ case CC_LOWER:
+ reg_addrange(preg, 'a', 'z');
+ break;
+ case CC_XDIGIT:
+ reg_addrange(preg, 'a', 'f');
+ reg_addrange(preg, 'A', 'F');
+
+ case CC_DIGIT:
+ reg_addrange(preg, '0', '9');
+ break;
+ case CC_CNTRL:
+ reg_addrange(preg, 0, 31);
+ reg_addrange(preg, 127, 127);
+ break;
+ case CC_PRINT:
+ reg_addrange(preg, ' ', '~');
+ break;
+ case CC_GRAPH:
+ reg_addrange(preg, '!', '~');
+ break;
+ case CC_PUNCT:
+ reg_addrange(preg, '!', '/');
+ reg_addrange(preg, ':', '@');
+ reg_addrange(preg, '[', '`');
+ reg_addrange(preg, '{', '~');
+ break;
+ }
+ continue;
+ }
+ }
+
+ reg_addrange(preg, start, start);
+ }
+ regc(preg, '\0');
+
+ if (*pattern) {
+ pattern++;
+ }
+ preg->regparse = pattern;
+
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(preg, 1, &flags);
+ if (ret == 0)
+ return 0;
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ preg->err = REG_ERR_INTERNAL;
+ return 0;
+ case '?':
+ case '+':
+ case '*':
+ case '{':
+ preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+ return 0;
+ case '\\':
+ ch = *preg->regparse++;
+ switch (ch) {
+ case '\0':
+ preg->err = REG_ERR_INVALID_ESCAPE;
+ return 0;
+ case 'A':
+ ret = regnode(preg, BOLX);
+ break;
+ case 'Z':
+ ret = regnode(preg, EOLX);
+ break;
+ case '<':
+ case 'm':
+ ret = regnode(preg, WORDA);
+ break;
+ case '>':
+ case 'M':
+ ret = regnode(preg, WORDZ);
+ break;
+ case 'd':
+ case 'D':
+ ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT);
+ reg_addrange(preg, '0', '9');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 'w':
+ case 'W':
+ ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT);
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ reg_addrange(preg, '0', '9');
+ reg_addrange(preg, '_', '_');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 's':
+ case 'S':
+ ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
+ reg_addrange_str(preg," \t\r\n\f\v");
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+
+ default:
+
+
+ preg->regparse--;
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default: {
+ int added = 0;
+
+
+ preg->regparse -= n;
+
+ ret = regnode(preg, EXACTLY);
+
+
+
+ while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+ n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+ if (ch == '\\' && preg->regparse[n]) {
+ if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
+
+ break;
+ }
+ n += reg_decode_escape(preg->regparse + n, &ch);
+ if (ch == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ }
+
+
+ if (ISMULT(preg->regparse[n])) {
+
+ if (added) {
+
+ break;
+ }
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ break;
+ }
+
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ }
+ regc(preg, '\0');
+
+ *flagp |= HASWIDTH;
+ if (added == 1)
+ *flagp |= SIMPLE;
+ break;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+ if (preg->p + n >= preg->proglen) {
+ preg->proglen = (preg->p + n) * 2;
+ preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+ }
+}
+
+
+static int regnode(regex_t *preg, int op)
+{
+ reg_grow(preg, 2);
+
+
+ preg->program[preg->p++] = op;
+ preg->program[preg->p++] = 0;
+
+
+ return preg->p - 2;
+}
+
+static void regc(regex_t *preg, int b )
+{
+ reg_grow(preg, 1);
+ preg->program[preg->p++] = b;
+}
+
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+ reg_grow(preg, size);
+
+
+ memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+
+ memset(preg->program + opnd, 0, sizeof(int) * size);
+
+ preg->program[opnd] = op;
+
+ preg->p += size;
+
+ return opnd + size;
+}
+
+static void regtail(regex_t *preg, int p, int val)
+{
+ int scan;
+ int temp;
+ int offset;
+
+
+ scan = p;
+ for (;;) {
+ temp = regnext(preg, scan);
+ if (temp == 0)
+ break;
+ scan = temp;
+ }
+
+ if (OP(preg, scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+
+ preg->program[scan + 1] = offset;
+}
+
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+
+ if (p != 0 && OP(preg, p) == BRANCH) {
+ regtail(preg, OPERAND(p), val);
+ }
+}
+
+
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+ const char *s;
+ int scan;
+
+
+ if (preg == NULL || preg->program == NULL || string == NULL) {
+ return REG_ERR_NULL_ARGUMENT;
+ }
+
+
+ if (*preg->program != REG_MAGIC) {
+ return REG_ERR_CORRUPTED;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "regexec: %s\n", string);
+ regdump(preg);
+#endif
+
+ preg->eflags = eflags;
+ preg->pmatch = pmatch;
+ preg->nmatch = nmatch;
+ preg->start = string;
+
+
+ for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
+ int op = OP(preg, scan);
+ if (op == END)
+ break;
+ if (op == REPX || op == REPXMIN)
+ preg->program[scan + 4] = 0;
+ }
+
+
+ if (preg->regmust != 0) {
+ s = string;
+ while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+ if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+ break;
+ }
+ s++;
+ }
+ if (s == NULL)
+ return REG_NOMATCH;
+ }
+
+
+ preg->regbol = string;
+
+
+ if (preg->reganch) {
+ if (eflags & REG_NOTBOL) {
+
+ goto nextline;
+ }
+ while (1) {
+ if (regtry(preg, string)) {
+ return REG_NOERROR;
+ }
+ if (*string) {
+nextline:
+ if (preg->cflags & REG_NEWLINE) {
+
+ string = strchr(string, '\n');
+ if (string) {
+ preg->regbol = ++string;
+ continue;
+ }
+ }
+ }
+ return REG_NOMATCH;
+ }
+ }
+
+
+ s = string;
+ if (preg->regstart != '\0') {
+
+ while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ s++;
+ }
+ }
+ else
+
+ while (1) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ if (*s == '\0') {
+ break;
+ }
+ else {
+ int c;
+ s += utf8_tounicode(s, &c);
+ }
+ }
+
+
+ return REG_NOMATCH;
+}
+
+
+static int regtry( regex_t *preg, const char *string )
+{
+ int i;
+
+ preg->reginput = string;
+
+ for (i = 0; i < preg->nmatch; i++) {
+ preg->pmatch[i].rm_so = -1;
+ preg->pmatch[i].rm_eo = -1;
+ }
+ if (regmatch(preg, 1)) {
+ preg->pmatch[0].rm_so = string - preg->start;
+ preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+ return(1);
+ } else
+ return(0);
+}
+
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+ const char *s = string;
+ while (proglen && *s) {
+ int ch;
+ int n = reg_utf8_tounicode_case(s, &ch, nocase);
+ if (ch != *prog) {
+ return -1;
+ }
+ prog++;
+ s += n;
+ proglen--;
+ }
+ if (proglen == 0) {
+ return s - string;
+ }
+ return -1;
+}
+
+static int reg_range_find(const int *range, int c)
+{
+ while (*range) {
+
+ if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+ return 1;
+ }
+ range += 2;
+ }
+ return 0;
+}
+
+static const char *str_find(const char *string, int c, int nocase)
+{
+ if (nocase) {
+
+ c = utf8_upper(c);
+ }
+ while (*string) {
+ int ch;
+ int n = reg_utf8_tounicode_case(string, &ch, nocase);
+ if (c == ch) {
+ return string;
+ }
+ string += n;
+ }
+ return NULL;
+}
+
+static int reg_iseol(regex_t *preg, int ch)
+{
+ if (preg->cflags & REG_NEWLINE) {
+ return ch == '\0' || ch == '\n';
+ }
+ else {
+ return ch == '\0';
+ }
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+ int nextch = '\0';
+ const char *save;
+ int no;
+ int c;
+
+ int max = preg->program[scan + 2];
+ int min = preg->program[scan + 3];
+ int next = regnext(preg, scan);
+
+ if (OP(preg, next) == EXACTLY) {
+ nextch = preg->program[OPERAND(next)];
+ }
+ save = preg->reginput;
+ no = regrepeat(preg, scan + 5, max);
+ if (no < min) {
+ return 0;
+ }
+ if (matchmin) {
+
+ max = no;
+ no = min;
+ }
+
+ while (1) {
+ if (matchmin) {
+ if (no > max) {
+ break;
+ }
+ }
+ else {
+ if (no < min) {
+ break;
+ }
+ }
+ preg->reginput = save + utf8_index(save, no);
+ reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ if (reg_iseol(preg, nextch) || c == nextch) {
+ if (regmatch(preg, next)) {
+ return(1);
+ }
+ }
+ if (matchmin) {
+
+ no++;
+ }
+ else {
+
+ no--;
+ }
+ }
+ return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+ int *scanpt = preg->program + scan;
+
+ int max = scanpt[2];
+ int min = scanpt[3];
+
+
+ if (scanpt[4] < min) {
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+ if (scanpt[4] > max) {
+ return 0;
+ }
+
+ if (matchmin) {
+
+ if (regmatch(preg, regnext(preg, scan))) {
+ return 1;
+ }
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+
+ if (scanpt[4] < max) {
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ }
+
+ return regmatch(preg, regnext(preg, scan));
+}
+
+
+static int regmatch(regex_t *preg, int prog)
+{
+ int scan;
+ int next;
+ const char *save;
+
+ scan = prog;
+
+#ifdef DEBUG
+ if (scan != 0 && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != 0) {
+ int n;
+ int c;
+#ifdef DEBUG
+ if (regnarrate) {
+ fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
+ }
+#endif
+ next = regnext(preg, scan);
+ n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ switch (OP(preg, scan)) {
+ case BOLX:
+ if ((preg->eflags & REG_NOTBOL)) {
+ return(0);
+ }
+
+ case BOL:
+ if (preg->reginput != preg->regbol) {
+ return(0);
+ }
+ break;
+ case EOLX:
+ if (c != 0) {
+
+ return 0;
+ }
+ break;
+ case EOL:
+ if (!reg_iseol(preg, c)) {
+ return(0);
+ }
+ break;
+ case WORDA:
+
+ if ((!isalnum(UCHAR(c))) && c != '_')
+ return(0);
+
+ if (preg->reginput > preg->regbol &&
+ (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+
+ if (preg->reginput > preg->regbol) {
+
+ if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
+ c = preg->reginput[-1];
+
+ if (isalnum(UCHAR(c)) || c == '_') {
+ break;
+ }
+ }
+ }
+
+ return(0);
+
+ case ANY:
+ if (reg_iseol(preg, c))
+ return 0;
+ preg->reginput += n;
+ break;
+ case EXACTLY: {
+ int opnd;
+ int len;
+ int slen;
+
+ opnd = OPERAND(scan);
+ len = str_int_len(preg->program + opnd);
+
+ slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+ if (slen < 0) {
+ return(0);
+ }
+ preg->reginput += slen;
+ }
+ break;
+ case ANYOF:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case ANYBUT:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case BRANCH:
+ if (OP(preg, next) != BRANCH)
+ next = OPERAND(scan);
+ else {
+ do {
+ save = preg->reginput;
+ if (regmatch(preg, OPERAND(scan))) {
+ return(1);
+ }
+ preg->reginput = save;
+ scan = regnext(preg, scan);
+ } while (scan != 0 && OP(preg, scan) == BRANCH);
+ return(0);
+
+ }
+ break;
+ case REP:
+ case REPMIN:
+ return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+ case REPX:
+ case REPXMIN:
+ return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+ case END:
+ return 1;
+
+ case OPENNC:
+ case CLOSENC:
+ return regmatch(preg, next);
+
+ default:
+ if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+ save = preg->reginput;
+ if (regmatch(preg, next)) {
+ if (OP(preg, scan) < CLOSE) {
+ int no = OP(preg, scan) - OPEN;
+ if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+ preg->pmatch[no].rm_so = save - preg->start;
+ }
+ }
+ else {
+ int no = OP(preg, scan) - CLOSE;
+ if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+ preg->pmatch[no].rm_eo = save - preg->start;
+ }
+ }
+ return(1);
+ }
+
+ preg->reginput = save;
+ return(0);
+ }
+ return REG_ERR_INTERNAL;
+ }
+
+ scan = next;
+ }
+
+ return REG_ERR_INTERNAL;
+}
+
+static int regrepeat(regex_t *preg, int p, int max)
+{
+ int count = 0;
+ const char *scan;
+ int opnd;
+ int ch;
+ int n;
+
+ scan = preg->reginput;
+ opnd = OPERAND(p);
+ switch (OP(preg, p)) {
+ case ANY:
+ while (!reg_iseol(preg, *scan) && count < max) {
+ count++;
+ scan += utf8_charlen(*scan);
+ }
+ break;
+ case EXACTLY:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (preg->program[opnd] != ch) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYOF:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYBUT:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ default:
+ preg->err = REG_ERR_INTERNAL;
+ count = 0;
+ break;
+ }
+ preg->reginput = scan;
+
+ return(count);
+}
+
+static int regnext(regex_t *preg, int p )
+{
+ int offset;
+
+ offset = NEXT(preg, p);
+
+ if (offset == 0)
+ return 0;
+
+ if (OP(preg, p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+static int regopsize(regex_t *preg, int p )
+{
+
+ switch (OP(preg, p)) {
+ case REP:
+ case REPMIN:
+ case REPX:
+ case REPXMIN:
+ return 5;
+
+ case ANYOF:
+ case ANYBUT:
+ case EXACTLY: {
+ int s = p + 2;
+ while (preg->program[s++]) {
+ }
+ return s - p;
+ }
+ }
+ return 2;
+}
+
+
+size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+ static const char *error_strings[] = {
+ "success",
+ "no match",
+ "bad pattern",
+ "null argument",
+ "unknown error",
+ "too big",
+ "out of memory",
+ "too many ()",
+ "parentheses () not balanced",
+ "braces {} not balanced",
+ "invalid repetition count(s)",
+ "extra characters",
+ "*+ of empty atom",
+ "nested count",
+ "internal error",
+ "count follows nothing",
+ "invalid escape \\ sequence",
+ "corrupted program",
+ "contains null char",
+ "brackets [] not balanced",
+ };
+ const char *err;
+
+ if (errcode < 0 || errcode >= REG_ERR_NUM) {
+ err = "Bad error code";
+ }
+ else {
+ err = error_strings[errcode];
+ }
+
+ return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void jim_regfree(regex_t *preg)
+{
+ free(preg->program);
+}
+
+#endif
+#include
+
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+ Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
+}
+
+#if defined(_WIN32) || defined(WIN32)
+#include
+
+int Jim_Errno(void)
+{
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: return ENOENT;
+ case ERROR_PATH_NOT_FOUND: return ENOENT;
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+ case ERROR_ACCESS_DENIED: return EACCES;
+ case ERROR_INVALID_HANDLE: return EBADF;
+ case ERROR_BAD_ENVIRONMENT: return E2BIG;
+ case ERROR_BAD_FORMAT: return ENOEXEC;
+ case ERROR_INVALID_ACCESS: return EACCES;
+ case ERROR_INVALID_DRIVE: return ENOENT;
+ case ERROR_CURRENT_DIRECTORY: return EACCES;
+ case ERROR_NOT_SAME_DEVICE: return EXDEV;
+ case ERROR_NO_MORE_FILES: return ENOENT;
+ case ERROR_WRITE_PROTECT: return EROFS;
+ case ERROR_BAD_UNIT: return ENXIO;
+ case ERROR_NOT_READY: return EBUSY;
+ case ERROR_BAD_COMMAND: return EIO;
+ case ERROR_CRC: return EIO;
+ case ERROR_BAD_LENGTH: return EIO;
+ case ERROR_SEEK: return EIO;
+ case ERROR_WRITE_FAULT: return EIO;
+ case ERROR_READ_FAULT: return EIO;
+ case ERROR_GEN_FAILURE: return EIO;
+ case ERROR_SHARING_VIOLATION: return EACCES;
+ case ERROR_LOCK_VIOLATION: return EACCES;
+ case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+ case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+ case ERROR_NOT_SUPPORTED: return ENODEV;
+ case ERROR_REM_NOT_LIST: return EBUSY;
+ case ERROR_DUP_NAME: return EEXIST;
+ case ERROR_BAD_NETPATH: return ENOENT;
+ case ERROR_NETWORK_BUSY: return EBUSY;
+ case ERROR_DEV_NOT_EXIST: return ENODEV;
+ case ERROR_TOO_MANY_CMDS: return EAGAIN;
+ case ERROR_ADAP_HDW_ERR: return EIO;
+ case ERROR_BAD_NET_RESP: return EIO;
+ case ERROR_UNEXP_NET_ERR: return EIO;
+ case ERROR_NETNAME_DELETED: return ENOENT;
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+ case ERROR_BAD_DEV_TYPE: return ENODEV;
+ case ERROR_BAD_NET_NAME: return ENOENT;
+ case ERROR_TOO_MANY_NAMES: return ENFILE;
+ case ERROR_TOO_MANY_SESS: return EIO;
+ case ERROR_SHARING_PAUSED: return EAGAIN;
+ case ERROR_REDIR_PAUSED: return EAGAIN;
+ case ERROR_FILE_EXISTS: return EEXIST;
+ case ERROR_CANNOT_MAKE: return ENOSPC;
+ case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+ case ERROR_ALREADY_ASSIGNED: return EEXIST;
+ case ERROR_INVALID_PASSWORD: return EPERM;
+ case ERROR_NET_WRITE_FAULT: return EIO;
+ case ERROR_NO_PROC_SLOTS: return EAGAIN;
+ case ERROR_DISK_CHANGE: return EXDEV;
+ case ERROR_BROKEN_PIPE: return EPIPE;
+ case ERROR_OPEN_FAILED: return ENOENT;
+ case ERROR_DISK_FULL: return ENOSPC;
+ case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+ case ERROR_INVALID_NAME: return ENOENT;
+ case ERROR_PROC_NOT_FOUND: return ESRCH;
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+ case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+ case ERROR_BUSY_DRIVE: return EAGAIN;
+ case ERROR_DIR_NOT_EMPTY: return EEXIST;
+ case ERROR_NOT_LOCKED: return EACCES;
+ case ERROR_BAD_PATHNAME: return ENOENT;
+ case ERROR_LOCK_FAILED: return EACCES;
+ case ERROR_ALREADY_EXISTS: return EEXIST;
+ case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+ case ERROR_BAD_PIPE: return EPIPE;
+ case ERROR_PIPE_BUSY: return EAGAIN;
+ case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+ case ERROR_DIRECTORY: return ENOTDIR;
+ }
+ return EINVAL;
+}
+
+long JimProcessPid(phandle_t pid)
+{
+ if (pid == INVALID_HANDLE_VALUE) {
+ return -1;
+ }
+ return GetProcessId(pid);
+}
+
+phandle_t JimWaitPid(long pid, int *status, int nohang)
+{
+ if (pid > 0) {
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
+ if (h) {
+ long pid = waitpid(h, status, nohang);
+ CloseHandle(h);
+ if (pid > 0) {
+ return h;
+ }
+ }
+ }
+ return JIM_BAD_PHANDLE;
+}
+
+long waitpid(phandle_t phandle, int *status, int nohang)
+{
+ long pid;
+ DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
+ if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+
+ return -1;
+ }
+ GetExitCodeProcess(phandle, &ret);
+ *status = ret;
+
+ pid = GetProcessId(phandle);
+ CloseHandle(phandle);
+ return pid;
+}
+
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
+{
+ char name[MAX_PATH];
+ HANDLE handle;
+
+ if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
+ return -1;
+ }
+
+ handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ goto error;
+ }
+
+ Jim_SetResultString(interp, name, -1);
+ return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);
+
+ error:
+ Jim_SetResultErrno(interp, name);
+ DeleteFile(name);
+ return -1;
+}
+
+int Jim_OpenForWrite(const char *filename, int append)
+{
+ if (strcmp(filename, "/dev/null") == 0) {
+ filename = "nul:";
+ }
+ int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
+ if (fd >= 0 && append) {
+
+ _lseek(fd, 0L, SEEK_END);
+ }
+ return fd;
+}
+
+int Jim_OpenForRead(const char *filename)
+{
+ if (strcmp(filename, "/dev/null") == 0) {
+ filename = "nul:";
+ }
+ return _open(filename, _O_RDONLY | _O_TEXT, 0);
+}
+
+#elif defined(HAVE_UNISTD_H)
+
+
+
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
+{
+ int fd;
+ mode_t mask;
+ Jim_Obj *filenameObj;
+
+ if (filename_template == NULL) {
+ const char *tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
+ tmpdir = "/tmp/";
+ }
+ filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
+ if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
+ Jim_AppendString(interp, filenameObj, "/", 1);
+ }
+ Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
+ }
+ else {
+ filenameObj = Jim_NewStringObj(interp, filename_template, -1);
+ }
+
+
+#ifdef HAVE_UMASK
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
+#ifdef HAVE_MKSTEMP
+ fd = mkstemp(filenameObj->bytes);
+#else
+ if (mktemp(filenameObj->bytes) == NULL) {
+ fd = -1;
+ }
+ else {
+ fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
+ }
+#endif
+#ifdef HAVE_UMASK
+ umask(mask);
+#endif
+ if (fd < 0) {
+ Jim_SetResultErrno(interp, Jim_String(filenameObj));
+ Jim_FreeNewObj(interp, filenameObj);
+ return -1;
+ }
+ if (unlink_file) {
+ remove(Jim_String(filenameObj));
+ }
+
+ Jim_SetResult(interp, filenameObj);
+ return fd;
+}
+
+int Jim_OpenForWrite(const char *filename, int append)
+{
+ return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+int Jim_OpenForRead(const char *filename)
+{
+ return open(filename, O_RDONLY, 0);
+}
+
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#if defined(HAVE_DLOPEN_COMPAT)
+void *dlopen(const char *path, int mode)
+{
+ JIM_NOTUSED(mode);
+
+ return (void *)LoadLibraryA(path);
+}
+
+int dlclose(void *handle)
+{
+ FreeLibrary((HANDLE)handle);
+ return 0;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+ return GetProcAddress((HMODULE)handle, symbol);
+}
+
+char *dlerror(void)
+{
+ static char msg[121];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
+ return msg;
+}
+#endif
+
+#ifdef _MSC_VER
+
+#include
+
+
+int gettimeofday(struct timeval *tv, void *unused)
+{
+ struct _timeb tb;
+
+ _ftime(&tb);
+ tv->tv_sec = tb.time;
+ tv->tv_usec = tb.millitm * 1000;
+
+ return 0;
+}
+
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if (name && name[0]) {
+ size_t base_length = strlen(name);
+ const char *all =
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
+ strcat(strcpy(dir->name, name), all);
+
+ if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
+ dir->result.d_name = 0;
+ else {
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ dir = 0;
+ }
+ }
+ else {
+ Jim_Free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else {
+ errno = EINVAL;
+ }
+ return dir;
+}
+
+int closedir(DIR * dir)
+{
+ int result = -1;
+
+ if (dir) {
+ if (dir->handle != -1)
+ result = _findclose(dir->handle);
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ }
+ if (result == -1)
+ errno = EBADF;
+ return result;
+}
+
+struct dirent *readdir(DIR * dir)
+{
+ struct dirent *result = 0;
+
+ if (dir && dir->handle != -1) {
+ if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return result;
+}
+#endif
+#endif
+#include
+#include
+
+
+
+
+
+
+#ifndef SIGPIPE
+#define SIGPIPE 13
+#endif
+#ifndef SIGINT
+#define SIGINT 2
+#endif
+
+const char *Jim_SignalId(int sig)
+{
+ static char buf[10];
+ switch (sig) {
+ case SIGINT: return "SIGINT";
+ case SIGPIPE: return "SIGPIPE";
+
+ }
+ snprintf(buf, sizeof(buf), "%d", sig);
+ return buf;
+}
+#ifndef JIM_BOOTSTRAP_LIB_ONLY
+#include
+#include
+#include
+
+
+#ifdef USE_LINENOISE
+#ifdef HAVE_UNISTD_H
+ #include
+#endif
+#ifdef HAVE_SYS_STAT_H
+ #include
+#endif
+#include "linenoise.h"
+#else
+#define MAX_LINE_LEN 512
+#endif
+
+#ifdef USE_LINENOISE
+struct JimCompletionInfo {
+ Jim_Interp *interp;
+ Jim_Obj *completion_command;
+ Jim_Obj *hints_command;
+
+};
+
+static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
+static const char completion_callback_assoc_key[] = "interactive-completion";
+static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
+static void JimFreeHintsCallback(void *hint, void *userdata);
+#endif
+
+char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+ char *result;
+ Jim_Obj *objPtr;
+ long mlmode = 0;
+ if (compinfo->completion_command) {
+ linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
+ }
+ if (compinfo->hints_command) {
+ linenoiseSetHintsCallback(JimHintsCallback, compinfo);
+ linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
+ }
+ objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
+ if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
+ linenoiseSetMultiLine(mlmode);
+ }
+
+ result = linenoise(prompt);
+
+ linenoiseSetCompletionCallback(NULL, NULL);
+ linenoiseSetHintsCallback(NULL, NULL);
+ linenoiseSetFreeHintsCallback(NULL);
+ return result;
+#else
+ int len;
+ char *line = Jim_Alloc(MAX_LINE_LEN);
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
+ Jim_Free(line);
+ return NULL;
+ }
+ len = strlen(line);
+ if (len && line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+ return line;
+#endif
+}
+
+void Jim_HistoryLoad(const char *filename)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryLoad(filename);
+#endif
+}
+
+void Jim_HistoryAdd(const char *line)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryAdd(line);
+#endif
+}
+
+void Jim_HistorySave(const char *filename)
+{
+#ifdef USE_LINENOISE
+#ifdef HAVE_UMASK
+ mode_t mask;
+
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
+#endif
+ linenoiseHistorySave(filename);
+#ifdef HAVE_UMASK
+ umask(mask);
+#endif
+#endif
+}
+
+void Jim_HistoryShow(void)
+{
+#ifdef USE_LINENOISE
+
+ int i;
+ int len;
+ char **history = linenoiseHistory(&len);
+ for (i = 0; i < len; i++) {
+ printf("%4d %s\n", i + 1, history[i]);
+ }
+#endif
+}
+
+void Jim_HistorySetMaxLen(int length)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistorySetMaxLen(length);
+#endif
+}
+
+int Jim_HistoryGetMaxLen(void)
+{
+#ifdef USE_LINENOISE
+ return linenoiseHistoryGetMaxLen();
+#endif
+ return 0;
+}
+
+#ifdef USE_LINENOISE
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+ int ret;
+
+ objv[0] = info->completion_command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+
+ if (ret == JIM_OK) {
+ int i;
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ int len = Jim_ListLength(info->interp, listObj);
+ for (i = 0; i < len; i++) {
+ linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
+ }
+ }
+}
+
+static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
+{
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+ Jim_Obj *objv[2];
+ int ret;
+ char *result = NULL;
+
+ objv[0] = info->hints_command;
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
+
+
+ if (ret == JIM_OK) {
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
+ Jim_IncrRefCount(listObj);
+
+ int len = Jim_ListLength(info->interp, listObj);
+ if (len >= 1) {
+ long x;
+ result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
+ if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
+ *color = x;
+ }
+ if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
+ *bold = x;
+ }
+ }
+ Jim_DecrRefCount(info->interp, listObj);
+ }
+ return result;
+}
+
+static void JimFreeHintsCallback(void *hint, void *userdata)
+{
+ Jim_Free(hint);
+}
+
+static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
+{
+ struct JimCompletionInfo *compinfo = data;
+
+ if (compinfo->completion_command) {
+ Jim_DecrRefCount(interp, compinfo->completion_command);
+ }
+ if (compinfo->hints_command) {
+ Jim_DecrRefCount(interp, compinfo->hints_command);
+ }
+
+ Jim_Free(compinfo);
+}
+
+static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
+{
+ struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
+ if (compinfo == NULL) {
+ compinfo = Jim_Alloc(sizeof(*compinfo));
+ compinfo->interp = interp;
+ compinfo->completion_command = NULL;
+ compinfo->hints_command = NULL;
+ Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
+ }
+ return compinfo;
+}
+#endif
+
+void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+
+ if (completionCommandObj) {
+
+ Jim_IncrRefCount(completionCommandObj);
+ }
+ if (compinfo->completion_command) {
+ Jim_DecrRefCount(interp, compinfo->completion_command);
+ }
+ compinfo->completion_command = completionCommandObj;
+#endif
+}
+
+void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
+{
+#ifdef USE_LINENOISE
+ struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
+
+ if (hintsCommandObj) {
+
+ Jim_IncrRefCount(hintsCommandObj);
+ }
+ if (compinfo->hints_command) {
+ Jim_DecrRefCount(interp, compinfo->hints_command);
+ }
+ compinfo->hints_command = hintsCommandObj;
+#endif
+}
+
+int Jim_InteractivePrompt(Jim_Interp *interp)
+{
+ int retcode = JIM_OK;
+ char *history_file = NULL;
+#ifdef USE_LINENOISE
+ const char *home;
+
+ home = getenv("HOME");
+ if (home && isatty(STDIN_FILENO)) {
+ int history_len = strlen(home) + sizeof("/.jim_history");
+ history_file = Jim_Alloc(history_len);
+ snprintf(history_file, history_len, "%s/.jim_history", home);
+ Jim_HistoryLoad(history_file);
+ }
+
+ Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
+ Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
+#endif
+
+ printf("Welcome to Jim version %d.%d\n",
+ JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
+
+ while (1) {
+ Jim_Obj *scriptObjPtr;
+ const char *result;
+ int reslen;
+ char prompt[20];
+
+ if (retcode != JIM_OK) {
+ const char *retcodestr = Jim_ReturnCode(retcode);
+
+ if (*retcodestr == '?') {
+ snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
+ }
+ else {
+ snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
+ }
+ }
+ else {
+ strcpy(prompt, ". ");
+ }
+
+ scriptObjPtr = Jim_NewStringObj(interp, "", 0);
+ Jim_IncrRefCount(scriptObjPtr);
+ while (1) {
+ char state;
+ char *line;
+
+ line = Jim_HistoryGetline(interp, prompt);
+ if (line == NULL) {
+ if (errno == EINTR) {
+ continue;
+ }
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ retcode = JIM_OK;
+ goto out;
+ }
+ if (Jim_Length(scriptObjPtr) != 0) {
+
+ Jim_AppendString(interp, scriptObjPtr, "\n", 1);
+ }
+ Jim_AppendString(interp, scriptObjPtr, line, -1);
+ Jim_Free(line);
+ if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
+ break;
+
+ snprintf(prompt, sizeof(prompt), "%c> ", state);
+ }
+#ifdef USE_LINENOISE
+ if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
+
+ Jim_HistoryShow();
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ continue;
+ }
+
+ Jim_HistoryAdd(Jim_String(scriptObjPtr));
+ if (history_file) {
+ Jim_HistorySave(history_file);
+ }
+#endif
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ if (retcode == JIM_EXIT) {
+ break;
+ }
+ if (retcode == JIM_ERR) {
+ Jim_MakeErrorMessage(interp);
+ }
+ result = Jim_GetString(Jim_GetResult(interp), &reslen);
+ if (reslen) {
+ if (fwrite(result, reslen, 1, stdout) == 0) {
+
+ }
+ putchar('\n');
+ }
+ }
+ out:
+ Jim_Free(history_file);
+
+ return retcode;
+}
+
+#include
+#include
+#include
+
+
+
+extern int Jim_initjimshInit(Jim_Interp *interp);
+
+static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
+{
+ int n;
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+
+ for (n = 0; n < argc; n++) {
+ Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
+
+ Jim_ListAppendElement(interp, listObj, obj);
+ }
+
+ Jim_SetVariableStr(interp, "argv", listObj);
+ Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
+}
+
+static void JimPrintErrorMessage(Jim_Interp *interp)
+{
+ Jim_MakeErrorMessage(interp);
+ fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+}
+
+void usage(const char* executable_name)
+{
+ printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+ printf("Usage: %s\n", executable_name);
+ printf("or : %s [options] [filename]\n", executable_name);
+ printf("\n");
+ printf("Without options: Interactive mode\n");
+ printf("\n");
+ printf("Options:\n");
+ printf(" --version : prints the version string\n");
+ printf(" --help : prints this text\n");
+ printf(" -e CMD : executes command CMD\n");
+ printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
+ printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
+ printf(" NOTE: all subsequent options will be passed to the script\n\n");
+}
+
+int main(int argc, char *const argv[])
+{
+ int retcode;
+ Jim_Interp *interp;
+ char *const orig_argv0 = argv[0];
+
+
+ if (argc > 1 && strcmp(argv[1], "--version") == 0) {
+ printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+ return 0;
+ }
+ else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
+ usage(argv[0]);
+ return 0;
+ }
+
+
+ interp = Jim_CreateInterp();
+ Jim_RegisterCoreCommands(interp);
+
+
+ if (Jim_InitStaticExtensions(interp) != JIM_OK) {
+ JimPrintErrorMessage(interp);
+ }
+
+ Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+#ifdef USE_LINENOISE
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
+#else
+ Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
+#endif
+ retcode = Jim_initjimshInit(interp);
+
+ if (argc == 1) {
+
+ if (retcode == JIM_ERR) {
+ JimPrintErrorMessage(interp);
+ }
+ if (retcode != JIM_EXIT) {
+ JimSetArgv(interp, 0, NULL);
+ if (!isatty(STDIN_FILENO)) {
+
+ goto eval_stdin;
+ }
+ retcode = Jim_InteractivePrompt(interp);
+ }
+ }
+ else {
+
+ if (argc > 2 && strcmp(argv[1], "-e") == 0) {
+
+ JimSetArgv(interp, argc - 3, argv + 3);
+ retcode = Jim_Eval(interp, argv[2]);
+ if (retcode != JIM_ERR) {
+ int len;
+ const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
+ if (fwrite(msg, len, 1, stdout) == 0) {
+
+ }
+ putchar('\n');
+ }
+ }
+ else {
+ Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
+ JimSetArgv(interp, argc - 2, argv + 2);
+ if (strcmp(argv[1], "-") == 0) {
+eval_stdin:
+ retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
+ } else {
+ retcode = Jim_EvalFile(interp, argv[1]);
+ }
+ }
+ if (retcode == JIM_ERR) {
+ JimPrintErrorMessage(interp);
+ }
+ }
+ if (retcode == JIM_EXIT) {
+ retcode = Jim_GetExitCode(interp);
+ }
+ else if (retcode == JIM_ERR) {
+ retcode = 1;
+ }
+ else {
+ retcode = 0;
+ }
+ Jim_FreeInterp(interp);
+ return retcode;
+}
+#endif
diff --git a/autosetup/pkg-config.tcl b/autosetup/pkg-config.tcl
new file mode 100644
index 0000000000..9ce7111f55
--- /dev/null
+++ b/autosetup/pkg-config.tcl
@@ -0,0 +1,168 @@
+# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'pkg-config' module allows package information to be found via 'pkg-config'.
+#
+# If not cross-compiling, the package path should be determined automatically
+# by 'pkg-config'.
+# If cross-compiling, the default package path is the compiler sysroot.
+# If the C compiler doesn't support '-print-sysroot', the path can be supplied
+# by the '--sysroot' option or by defining 'SYSROOT'.
+#
+# 'PKG_CONFIG' may be set to use an alternative to 'pkg-config'.
+
+use cc
+
+options {
+ sysroot:dir => "Override compiler sysroot for pkg-config search path"
+}
+
+# @pkg-config-init ?required?
+#
+# Initialises the 'pkg-config' system. Unless '$required' is set to 0,
+# it is a fatal error if a usable 'pkg-config' is not found .
+#
+# This command will normally be called automatically as required,
+# but it may be invoked explicitly if lack of 'pkg-config' is acceptable.
+#
+# Returns 1 if ok, or 0 if 'pkg-config' not found/usable (only if '$required' is 0).
+#
+proc pkg-config-init {{required 1}} {
+ if {[is-defined HAVE_PKG_CONFIG]} {
+ return [get-define HAVE_PKG_CONFIG]
+ }
+ set found 0
+
+ define PKG_CONFIG [get-env PKG_CONFIG pkg-config]
+ msg-checking "Checking for pkg-config..."
+
+ if {[catch {exec [get-define PKG_CONFIG] --version} version]} {
+ msg-result "[get-define PKG_CONFIG] (not found)"
+ if {$required} {
+ user-error "No usable pkg-config"
+ }
+ } else {
+ msg-result $version
+ define PKG_CONFIG_VERSION $version
+
+ set found 1
+
+ if {[opt-str sysroot o]} {
+ define SYSROOT [file-normalize $o]
+ msg-result "Using specified sysroot [get-define SYSROOT]"
+ } elseif {[get-define build] ne [get-define host]} {
+ if {[catch {exec-with-stderr {*}[get-define CC] -print-sysroot} result errinfo] == 0} {
+ # Use the compiler sysroot, if there is one
+ define SYSROOT $result
+ msg-result "Found compiler sysroot $result"
+ } else {
+ configlog "[get-define CC] -print-sysroot: $result"
+ set msg "pkg-config: Cross compiling, but no compiler sysroot and no --sysroot supplied"
+ if {$required} {
+ user-error $msg
+ } else {
+ msg-result $msg
+ }
+ set found 0
+ }
+ }
+ if {[is-defined SYSROOT]} {
+ set sysroot [get-define SYSROOT]
+
+ # XXX: It's possible that these should be set only when invoking pkg-config
+ global env
+ set env(PKG_CONFIG_DIR) ""
+ # Supposedly setting PKG_CONFIG_LIBDIR means that PKG_CONFIG_PATH is ignored,
+ # but it doesn't seem to work that way in practice
+ set env(PKG_CONFIG_PATH) ""
+ # Do we need to try /usr/local as well or instead?
+ set env(PKG_CONFIG_LIBDIR) $sysroot/usr/lib/pkgconfig:$sysroot/usr/share/pkgconfig
+ set env(PKG_CONFIG_SYSROOT_DIR) $sysroot
+ }
+ }
+ define HAVE_PKG_CONFIG $found
+ return $found
+}
+
+# @pkg-config module ?requirements?
+#
+# Use 'pkg-config' to find the given module meeting the given requirements.
+# e.g.
+#
+## pkg-config pango >= 1.37.0
+#
+# If found, returns 1 and sets 'HAVE_PKG_PANGO' to 1 along with:
+#
+## PKG_PANGO_VERSION to the found version
+## PKG_PANGO_LIBS to the required libs (--libs-only-l)
+## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
+## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
+#
+# If not found, returns 0.
+#
+proc pkg-config {module args} {
+ set ok [pkg-config-init]
+
+ msg-checking "Checking for $module $args..."
+
+ if {!$ok} {
+ msg-result "no pkg-config"
+ return 0
+ }
+
+ set pkgconfig [get-define PKG_CONFIG]
+
+ set ret [catch {exec $pkgconfig --modversion "$module $args"} version]
+ configlog "$pkgconfig --modversion $module $args: $version"
+ if {$ret} {
+ msg-result "not found"
+ return 0
+ }
+ # Sometimes --modversion succeeds but because of dependencies it isn't usable
+ # This seems to show up with --cflags
+ set ret [catch {exec $pkgconfig --cflags $module} cflags]
+ if {$ret} {
+ msg-result "unusable ($version - see config.log)"
+ configlog "$pkgconfig --cflags $module"
+ configlog $cflags
+ return 0
+ }
+ msg-result $version
+ set prefix [feature-define-name $module PKG_]
+ define HAVE_${prefix}
+ define ${prefix}_VERSION $version
+ define ${prefix}_CFLAGS $cflags
+ define ${prefix}_LIBS [exec $pkgconfig --libs-only-l $module]
+ define ${prefix}_LDFLAGS [exec $pkgconfig --libs-only-L $module]
+ return 1
+}
+
+# @pkg-config-get module setting
+#
+# Convenience access to the results of 'pkg-config'.
+#
+# For example, '[pkg-config-get pango CFLAGS]' returns
+# the value of 'PKG_PANGO_CFLAGS', or '""' if not defined.
+proc pkg-config-get {module name} {
+ set prefix [feature-define-name $module PKG_]
+ get-define ${prefix}_${name} ""
+}
+
+# @pkg-config-get-var module variable
+#
+# Return the value of the given variable from the given pkg-config module.
+# The module must already have been successfully detected with pkg-config.
+# e.g.
+#
+## if {[pkg-config harfbuzz >= 2.5]} {
+## define harfbuzz_libdir [pkg-config-get-var harfbuzz libdir]
+## }
+#
+# Returns the empty string if the variable isn't defined.
+proc pkg-config-get-var {module variable} {
+ set pkgconfig [get-define PKG_CONFIG]
+ set prefix [feature-define-name $module HAVE_PKG_]
+ exec $pkgconfig $module --variable $variable
+}
diff --git a/autosetup/proj.tcl b/autosetup/proj.tcl
new file mode 100644
index 0000000000..4be268da6a
--- /dev/null
+++ b/autosetup/proj.tcl
@@ -0,0 +1,1306 @@
+########################################################################
+# 2024 September 25
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# * May you do good and not evil.
+# * May you find forgiveness for yourself and forgive others.
+# * May you share freely, never taking more than you give.
+#
+########################################################################
+# Routines for Steve Bennett's autosetup which are common to trees
+# managed in and around the umbrella of the SQLite project.
+#
+# The intent is that these routines be relatively generic, independent
+# of a given project.
+#
+# This file was initially derived from one used in the libfossil
+# project, authored by the same person who ported it here, and this is
+# noted here only as an indication that there are no licensing issues
+# despite this code having a handful of near-twins running around a
+# handful of third-party source trees.
+#
+########################################################################
+#
+# Design notes:
+#
+# - Symbols with a suffix of _ are intended for internal use within
+# this file, and are not part of the API which auto.def files should
+# rely on.
+#
+# - By and large, autosetup prefers to update global state with the
+# results of feature checks, e.g. whether the compiler supports flag
+# --X. In this developer's opinion that (A) causes more confusion
+# than it solves[^1] and (B) adds an unnecessary layer of "voodoo"
+# between the autosetup user and its internals. This module, in
+# contrast, instead injects the results of its own tests into
+# well-defined variables and leaves the integration of those values
+# to the caller's discretion.
+#
+# [1]: As an example: testing for the -rpath flag, using
+# cc-check-flags, can break later checks which use
+# [cc-check-function-in-lib ...] because the resulting -rpath flag
+# implicitly becomes part of those tests. In the case of an rpath
+# test, downstream tests may not like the $prefix/lib path added by
+# the rpath test. To avoid such problems, we avoid (intentionally)
+# updating global state via feature tests.
+########################################################################
+
+# ----- @module proj.tcl -----
+# @section Project Helper APIs
+
+########################################################################
+# $proj_ is an internal-use-only array for storing whatever generic
+# internal stuff we need stored.
+array set proj_ {}
+set proj_(isatty) [isatty? stdout]
+
+########################################################################
+# @proj-warn msg
+#
+# Emits a warning message to stderr.
+proc proj-warn {msg} {
+ show-notices
+ puts stderr "WARNING: $msg"
+}
+########################################################################
+# @proj-error msg
+#
+# Emits an error message to stderr and exits with non-0.
+proc proj-fatal {msg} {
+ show-notices
+ puts stderr "ERROR: $msg"
+ exit 1
+}
+
+########################################################################
+# @proj-assert script
+#
+# Kind of like a C assert: if uplevel (eval) of [expr {$script}] is
+# false, a fatal error is triggered. The error message, by default,
+# includes the body of the failed assertion, but if $descr is set then
+# that is used instead.
+proc proj-assert {script {descr ""}} {
+ if {1 == [get-env proj-assert 0]} {
+ msg-result [proj-bold "asserting: $script"]
+ }
+ set x "expr \{ $script \}"
+ if {![uplevel 1 $x]} {
+ if {"" eq $descr} {
+ set descr $script
+ }
+ proj-fatal "Assertion failed: $descr"
+ }
+}
+
+########################################################################
+# @proj-bold str
+#
+# If this function believes that the current console might support
+# ANSI escape sequences then this returns $str wrapped in a sequence
+# to bold that text, else it returns $str as-is.
+proc proj-bold {str} {
+ if {$::autosetup(iswin) || !$::proj_(isatty)} {
+ return $str
+ }
+ return "\033\[1m${str}\033\[0m"
+}
+
+########################################################################
+# @proj-indented-notice ?-error? ?-notice? msg
+#
+# Takes a multi-line message and emits it with consistent indentation.
+#
+# If the -notice flag it used then it emits using [user-notice], which
+# means its rendering will (A) go to stderr and (B) be delayed until
+# the next time autosetup goes to output a message.
+#
+# If the -error flag is provided then it renders the message
+# immediately to stderr and then exits.
+#
+# If neither -notice nor -error are used, the message will be sent to
+# stdout without delay.
+proc proj-indented-notice {args} {
+ set fErr ""
+ set outFunc "puts"
+ while {[llength $args] > 1} {
+ switch -exact -- [lindex $args 0] {
+ -error {
+ set args [lassign $args fErr]
+ set outFunc "user-notice"
+ }
+ -notice {
+ set args [lassign $args -]
+ set outFunc "user-notice"
+ }
+ default {
+ break
+ }
+ }
+ }
+ set lines [split [join $args] \n]
+ foreach line $lines {
+ set line [string trimleft $line]
+ if {"" eq $line} {
+ $outFunc $line
+ } else {
+ $outFunc " $line"
+ }
+ }
+ if {"" ne $fErr} {
+ show-notices
+ exit 1
+ }
+}
+
+########################################################################
+# @proj-is-cross-compiling
+#
+# Returns 1 if cross-compiling, else 0.
+proc proj-is-cross-compiling {} {
+ return [expr {[get-define host] ne [get-define build]}]
+}
+
+########################################################################
+# proj-lshift_ shifts $count elements from the list named $listVar
+# and returns them as a new list. On empty input, returns "".
+#
+# Modified slightly from: https://wiki.tcl-lang.org/page/lshift
+proc proj-lshift_ {listVar {count 1}} {
+ upvar 1 $listVar l
+ if {![info exists l]} {
+ # make the error message show the real variable name
+ error "can't read \"$listVar\": no such variable"
+ }
+ if {![llength $l]} {
+ # error Empty
+ return ""
+ }
+ set r [lrange $l 0 [incr count -1]]
+ set l [lreplace $l [set l 0] $count]
+ return $r
+}
+
+########################################################################
+# Expects to receive string input, which it splits on newlines, strips
+# out any lines which begin with an number of whitespace followed by a
+# '#', and returns a value containing the [append]ed results of each
+# remaining line with a \n between each.
+proc proj-strip-hash-comments {val} {
+ set x {}
+ foreach line [split $val \n] {
+ if {![string match "#*" [string trimleft $line]]} {
+ append x $line \n
+ }
+ }
+ return $x
+}
+
+########################################################################
+# @proj-check-function-in-lib
+#
+# A proxy for cc-check-function-in-lib which does not make any global
+# changes to the LIBS define. Returns the result of
+# cc-check-function-in-lib (i.e. true or false). The resulting linker
+# flags are stored in ${lib_${function}}.
+proc proj-check-function-in-lib {function libs {otherlibs {}}} {
+ set found 0
+ define-push {LIBS} {
+ set found [cc-check-function-in-lib $function $libs $otherlibs]
+ }
+ return $found
+}
+
+########################################################################
+# @proj-search-for-header-dir ?-dirs LIST? ?-subdirs LIST? header
+#
+# Searches for $header in a combination of dirs and subdirs, specified
+# by the -dirs {LIST} and -subdirs {LIST} flags (each of which have
+# sane defaults). Returns either the first matching dir or an empty
+# string. The return value does not contain the filename part.
+proc proj-search-for-header-dir {header args} {
+ set subdirs {include}
+ set dirs {/usr /usr/local /mingw}
+# Debatable:
+# if {![proj-is-cross-compiling]} {
+# lappend dirs [get-define prefix]
+# }
+ while {[llength $args]} {
+ switch -exact -- [lindex $args 0] {
+ -dirs { set args [lassign $args - dirs] }
+ -subdirs { set args [lassign $args - subdirs] }
+ default {
+ proj-fatal "Unhandled argument: $args"
+ }
+ }
+ }
+ foreach dir $dirs {
+ foreach sub $subdirs {
+ if {[file exists $dir/$sub/$header]} {
+ return "$dir/$sub"
+ }
+ }
+ }
+ return ""
+}
+
+########################################################################
+# @proj-find-executable-path ?-v? binaryName
+#
+# Works similarly to autosetup's [find-executable-path $binName] but:
+#
+# - If the first arg is -v, it's verbose about searching, else it's quiet.
+#
+# Returns the full path to the result or an empty string.
+proc proj-find-executable-path {args} {
+ set binName $args
+ set verbose 0
+ if {[lindex $args 0] eq "-v"} {
+ set verbose 1
+ set args [lassign $args - binName]
+ msg-checking "Looking for $binName ... "
+ }
+ set check [find-executable-path $binName]
+ if {$verbose} {
+ if {"" eq $check} {
+ msg-result "not found"
+ } else {
+ msg-result $check
+ }
+ }
+ return $check
+}
+
+########################################################################
+# @proj-bin-define binName ?defName?
+#
+# Uses [proj-find-executable-path $binName] to (verbosely) search for
+# a binary, sets a define (see below) to the result, and returns the
+# result (an empty string if not found).
+#
+# The define'd name is: If $defName is not empty, it is used as-is. If
+# $defName is empty then "BIN_X" is used, where X is the upper-case
+# form of $binName with any '-' characters replaced with '_'.
+proc proj-bin-define {binName {defName {}}} {
+ set check [proj-find-executable-path -v $binName]
+ if {"" eq $defName} {
+ set defName "BIN_[string toupper [string map {- _} $binName]]"
+ }
+ define $defName $check
+ return $check
+}
+
+########################################################################
+# @proj-first-bin-of bin...
+#
+# Looks for the first binary found of the names passed to this
+# function. If a match is found, the full path to that binary is
+# returned, else "" is returned.
+#
+# Despite using cc-path-progs to do the search, this function clears
+# any define'd name that function stores for the result (because the
+# caller has no sensible way of knowing which result it was unless
+# they pass only a single argument).
+proc proj-first-bin-of {args} {
+ set rc ""
+ foreach b $args {
+ set u [string toupper $b]
+ # Note that cc-path-progs defines $u to false if it finds no match.
+ if {[cc-path-progs $b]} {
+ set rc [get-define $u]
+ }
+ undefine $u
+ if {"" ne $rc} break
+ }
+ return $rc
+}
+
+########################################################################
+# @proj-opt-was-provided key
+#
+# Returns 1 if the user specifically provided the given configure flag
+# or if it was specifically set using proj-opt-set, else 0. This can
+# be used to distinguish between options which have a default value
+# and those which were explicitly provided by the user, even if the
+# latter is done in a way which uses the default value.
+#
+# For example, with a configure flag defined like:
+#
+# { foo-bar:=baz => {its help text} }
+#
+# This function will, when passed foo-bar, return 1 only if the user
+# passes --foo-bar to configure, even if that invocation would resolve
+# to the default value of baz. If the user does not explicitly pass in
+# --foo-bar (with or without a value) then this returns 0.
+#
+# Note: unlike most functions which deal with configure --flags, this
+# one does not validate that $key refers to a pre-defined flag. i.e.
+# it accepts arbitrary keys, even those not defined via an [options]
+# call. [proj-opt-set] manipulates the internal list of flags, such
+# that new options set via that function will cause this function to
+# return true. (That's an unintended and unavoidable side-effect, not
+# specifically a feature which should be made use of.)
+proc proj-opt-was-provided {key} {
+ dict exists $::autosetup(optset) $key
+}
+
+########################################################################
+# @proj-opt-set flag ?val?
+#
+# Force-set autosetup option $flag to $val. The value can be fetched
+# later with [opt-val], [opt-bool], and friends.
+#
+# Returns $val.
+proc proj-opt-set {flag {val 1}} {
+ if {$flag ni $::autosetup(options)} {
+ # We have to add this to autosetup(options) or else future calls
+ # to [opt-bool $flag] will fail validation of $flag.
+ lappend ::autosetup(options) $flag
+ }
+ dict set ::autosetup(optset) $flag $val
+ return $val
+}
+
+########################################################################
+# @proj-opt-exists flag
+#
+# Returns 1 if the given flag has been defined as a legal configure
+# option, else returns 0.
+proc proj-opt-exists {flag} {
+ expr {$flag in $::autosetup(options)};
+}
+
+########################################################################
+# @proj-val-truthy val
+#
+# Returns 1 if $val appears to be a truthy value, else returns
+# 0. Truthy values are any of {1 on true yes enabled}
+proc proj-val-truthy {val} {
+ expr {$val in {1 on true yes enabled}}
+}
+
+########################################################################
+# @proj-opt-truthy flag
+#
+# Returns 1 if [opt-val $flag] appears to be a truthy value or
+# [opt-bool $flag] is true. See proj-val-truthy.
+proc proj-opt-truthy {flag} {
+ if {[proj-val-truthy [opt-val $flag]]} { return 1 }
+ set rc 0
+ catch {
+ # opt-bool will throw if $flag is not a known boolean flag
+ set rc [opt-bool $flag]
+ }
+ return $rc
+}
+
+########################################################################
+# @proj-if-opt-truthy boolFlag thenScript ?elseScript?
+#
+# If [proj-opt-truthy $flag] is true, eval $then, else eval $else.
+proc proj-if-opt-truthy {boolFlag thenScript {elseScript {}}} {
+ if {[proj-opt-truthy $boolFlag]} {
+ uplevel 1 $thenScript
+ } else {
+ uplevel 1 $elseScript
+ }
+}
+
+########################################################################
+# @proj-define-for-opt flag def ?msg? ?iftrue? ?iffalse?
+#
+# If [proj-opt-truthy $flag] then [define $def $iftrue] else [define
+# $def $iffalse]. If $msg is not empty, output [msg-checking $msg] and
+# a [msg-results ...] which corresponds to the result. Returns 1 if
+# the opt-truthy check passes, else 0.
+proc proj-define-for-opt {flag def {msg ""} {iftrue 1} {iffalse 0}} {
+ if {"" ne $msg} {
+ msg-checking "$msg "
+ }
+ set rcMsg ""
+ set rc 0
+ if {[proj-opt-truthy $flag]} {
+ define $def $iftrue
+ set rc 1
+ } else {
+ define $def $iffalse
+ }
+ switch -- [proj-val-truthy [get-define $def]] {
+ 0 { set rcMsg no }
+ 1 { set rcMsg yes }
+ }
+ if {"" ne $msg} {
+ msg-result $rcMsg
+ }
+ return $rc
+}
+
+########################################################################
+# @proj-opt-define-bool ?-v? optName defName ?descr?
+#
+# Checks [proj-opt-truthy $optName] and calls [define $defName X]
+# where X is 0 for false and 1 for true. descr is an optional
+# [msg-checking] argument which defaults to $defName. Returns X.
+#
+# If args[0] is -v then the boolean semantics are inverted: if
+# the option is set, it gets define'd to 0, else 1. Returns the
+# define'd value.
+proc proj-opt-define-bool {args} {
+ set invert 0
+ if {[lindex $args 0] eq "-v"} {
+ set invert 1
+ set args [lrange $args 1 end]
+ }
+ set optName [proj-lshift_ args]
+ set defName [proj-lshift_ args]
+ set descr [proj-lshift_ args]
+ if {"" eq $descr} {
+ set descr $defName
+ }
+ set rc 0
+ msg-checking "$descr ... "
+ if {[proj-opt-truthy $optName]} {
+ if {0 eq $invert} {
+ set rc 1
+ } else {
+ set rc 0
+ }
+ } elseif {0 ne $invert} {
+ set rc 1
+ }
+ msg-result $rc
+ define $defName $rc
+ return $rc
+}
+
+########################################################################
+# @proj-check-module-loader
+#
+# Check for module-loading APIs (libdl/libltdl)...
+#
+# Looks for libltdl or dlopen(), the latter either in -ldl or built in
+# to libc (as it is on some platforms). Returns 1 if found, else
+# 0. Either way, it `define`'s:
+#
+# - HAVE_LIBLTDL to 1 or 0 if libltdl is found/not found
+# - HAVE_LIBDL to 1 or 0 if dlopen() is found/not found
+# - LDFLAGS_MODULE_LOADER one of ("-lltdl", "-ldl", or ""), noting
+# that -ldl may legally be empty on some platforms even if
+# HAVE_LIBDL is true (indicating that dlopen() is available without
+# extra link flags). LDFLAGS_MODULE_LOADER also gets "-rdynamic" appended
+# to it because otherwise trying to open DLLs will result in undefined
+# symbol errors.
+#
+# Note that if it finds LIBLTDL it does not look for LIBDL, so will
+# report only that is has LIBLTDL.
+proc proj-check-module-loader {} {
+ msg-checking "Looking for module-loader APIs... "
+ if {99 ne [get-define LDFLAGS_MODULE_LOADER 99]} {
+ if {1 eq [get-define HAVE_LIBLTDL 0]} {
+ msg-result "(cached) libltdl"
+ return 1
+ } elseif {1 eq [get-define HAVE_LIBDL 0]} {
+ msg-result "(cached) libdl"
+ return 1
+ }
+ # else: wha???
+ }
+ set HAVE_LIBLTDL 0
+ set HAVE_LIBDL 0
+ set LDFLAGS_MODULE_LOADER ""
+ set rc 0
+ puts "" ;# cosmetic kludge for cc-check-XXX
+ if {[cc-check-includes ltdl.h] && [cc-check-function-in-lib lt_dlopen ltdl]} {
+ set HAVE_LIBLTDL 1
+ set LDFLAGS_MODULE_LOADER "-lltdl -rdynamic"
+ msg-result " - Got libltdl."
+ set rc 1
+ } elseif {[cc-with {-includes dlfcn.h} {
+ cctest -link 1 -declare "extern char* dlerror(void);" -code "dlerror();"}]} {
+ msg-result " - This system can use dlopen() without -ldl."
+ set HAVE_LIBDL 1
+ set LDFLAGS_MODULE_LOADER ""
+ set rc 1
+ } elseif {[cc-check-includes dlfcn.h]} {
+ set HAVE_LIBDL 1
+ set rc 1
+ if {[cc-check-function-in-lib dlopen dl]} {
+ msg-result " - dlopen() needs libdl."
+ set LDFLAGS_MODULE_LOADER "-ldl -rdynamic"
+ } else {
+ msg-result " - dlopen() not found in libdl. Assuming dlopen() is built-in."
+ set LDFLAGS_MODULE_LOADER "-rdynamic"
+ }
+ }
+ define HAVE_LIBLTDL $HAVE_LIBLTDL
+ define HAVE_LIBDL $HAVE_LIBDL
+ define LDFLAGS_MODULE_LOADER $LDFLAGS_MODULE_LOADER
+ return $rc
+}
+
+########################################################################
+# @proj-no-check-module-loader
+#
+# Sets all flags which would be set by proj-check-module-loader to
+# empty/falsy values, as if those checks had failed to find a module
+# loader. Intended to be called in place of that function when
+# a module loader is explicitly not desired.
+proc proj-no-check-module-loader {} {
+ define HAVE_LIBDL 0
+ define HAVE_LIBLTDL 0
+ define LDFLAGS_MODULE_LOADER ""
+}
+
+########################################################################
+# @proj-file-conent ?-trim? filename
+#
+# Opens the given file, reads all of its content, and returns it. If
+# the first arg is -trim, the contents of the file named by the second
+# argument are trimmed before returning them.
+proc proj-file-content {args} {
+ set trim 0
+ set fname $args
+ if {"-trim" eq [lindex $args 0]} {
+ set trim 1
+ lassign $args - fname
+ }
+ set fp [open $fname r]
+ set rc [read $fp]
+ close $fp
+ if {$trim} { return [string trim $rc] }
+ return $rc
+}
+
+########################################################################
+# @proj-file-conent filename
+#
+# Returns the contents of the given file as an array of lines, with
+# the EOL stripped from each input line.
+proc proj-file-content-list {fname} {
+ set fp [open $fname r]
+ set rc {}
+ while { [gets $fp line] >= 0 } {
+ lappend rc $line
+ }
+ close $fp
+ return $rc
+}
+
+########################################################################
+# @proj-check-compile-commands ?configFlag?
+#
+# Checks the compiler for compile_commands.json support. If passed an
+# argument it is assumed to be the name of an autosetup boolean config
+# which controls whether to run/skip this check.
+#
+# Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes"
+# if supported, "no" if not.
+#
+# This test has a long history of false positive results because of
+# compilers reacting differently to the -MJ flag.
+proc proj-check-compile-commands {{configFlag {}}} {
+ msg-checking "compile_commands.json support... "
+ if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} {
+ msg-result "explicitly disabled"
+ define MAKE_COMPILATION_DB no
+ return 0
+ } else {
+ if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
+ # This test reportedly incorrectly succeeds on one of
+ # Martin G.'s older systems. drh also reports a false
+ # positive on an unspecified older Mac system.
+ msg-result "compiler supports compile_commands.json"
+ define MAKE_COMPILATION_DB yes
+ return 1
+ } else {
+ msg-result "compiler does not support compile_commands.json"
+ define MAKE_COMPILATION_DB no
+ return 0
+ }
+ }
+}
+
+########################################################################
+# @proj-touch filename
+#
+# Runs the 'touch' external command on one or more files, ignoring any
+# errors.
+proc proj-touch {filename} {
+ catch { exec touch {*}$filename }
+}
+
+########################################################################
+# @proj-make-from-dot-in ?-touch? filename...
+#
+# Uses [make-template] to create makefile(-like) file(s) $filename
+# from $filename.in but explicitly makes the output read-only, to
+# avoid inadvertent editing (who, me?).
+#
+# If the first argument is -touch then the generated file is touched
+# to update its timestamp. This can be used as a workaround for
+# cases where (A) autosetup does not update the file because it was
+# not really modified and (B) the file *really* needs to be updated to
+# please the build process.
+#
+# Failures when running chmod or touch are silently ignored.
+proc proj-make-from-dot-in {args} {
+ set filename $args
+ set touch 0
+ if {[lindex $args 0] eq "-touch"} {
+ set touch 1
+ set filename [lrange $args 1 end]
+ }
+ foreach f $filename {
+ set f [string trim $f]
+ catch { exec chmod u+w $f }
+ make-template $f.in $f
+ if {$touch} {
+ proj-touch $f
+ }
+ catch { exec chmod -w $f }
+ }
+}
+
+########################################################################
+# @proj-check-profile-flag ?flagname?
+#
+# Checks for the boolean configure option named by $flagname. If set,
+# it checks if $CC seems to refer to gcc. If it does (or appears to)
+# then it defines CC_PROFILE_FLAG to "-pg" and returns 1, else it
+# defines CC_PROFILE_FLAG to "" and returns 0.
+#
+# Note that the resulting flag must be added to both CFLAGS and
+# LDFLAGS in order for binaries to be able to generate "gmon.out". In
+# order to avoid potential problems with escaping, space-containing
+# tokens, and interfering with autosetup's use of these vars, this
+# routine does not directly modify CFLAGS or LDFLAGS.
+proc proj-check-profile-flag {{flagname profile}} {
+ #puts "flagname=$flagname ?[proj-opt-truthy $flagname]?"
+ if {[proj-opt-truthy $flagname]} {
+ set CC [get-define CC]
+ regsub {.*ccache *} $CC "" CC
+ # ^^^ if CC="ccache gcc" then [exec] treats "ccache gcc" as a
+ # single binary name and fails. So strip any leading ccache part
+ # for this purpose.
+ if { ![catch { exec $CC --version } msg]} {
+ if {[string first gcc $CC] != -1} {
+ define CC_PROFILE_FLAG "-pg"
+ return 1
+ }
+ }
+ }
+ define CC_PROFILE_FLAG ""
+ return 0
+}
+
+########################################################################
+# @proj-looks-like-windows ?key?
+#
+# Returns 1 if this appears to be a Windows environment (MinGw,
+# Cygwin, MSys), else returns 0. The optional argument is the name of
+# an autosetup define which contains platform name info, defaulting to
+# "host" (meaning, somewhat counterintuitively, the target system, not
+# the current host). The other legal value is "build" (the build
+# machine, i.e. the local host). If $key == "build" then some
+# additional checks may be performed which are not applicable when
+# $key == "host".
+proc proj-looks-like-windows {{key host}} {
+ global autosetup
+ switch -glob -- [get-define $key] {
+ *-*-ming* - *-*-cygwin - *-*-msys - *windows* {
+ return 1
+ }
+ }
+ if {$key eq "build"} {
+ # These apply only to the local OS, not a cross-compilation target,
+ # as the above check potentially can.
+ if {$::autosetup(iswin)} { return 1 }
+ if {[find-an-executable cygpath] ne "" || $::tcl_platform(os)=="Windows NT"} {
+ return 1
+ }
+ }
+ return 0
+}
+
+########################################################################
+# @proj-looks-like-mac ?key?
+#
+# Looks at either the 'host' (==compilation target platform) or
+# 'build' (==the being-built-on platform) define value and returns if
+# if that value seems to indicate that it represents a Mac platform,
+# else returns 0.
+proc proj-looks-like-mac {{key host}} {
+ switch -glob -- [get-define $key] {
+ *apple* {
+ return 1
+ }
+ default {
+ return 0
+ }
+ }
+}
+
+########################################################################
+# @proj-exe-extension
+#
+# Checks autosetup's "host" and "build" defines to see if the build
+# host and target are Windows-esque (Cygwin, MinGW, MSys). If the
+# build environment is then BUILD_EXEEXT is [define]'d to ".exe", else
+# "". If the target, a.k.a. "host", is then TARGET_EXEEXT is
+# [define]'d to ".exe", else "".
+proc proj-exe-extension {} {
+ set rH ""
+ set rB ""
+ if {[proj-looks-like-windows host]} {
+ set rH ".exe"
+ }
+ if {[proj-looks-like-windows build]} {
+ set rB ".exe"
+ }
+ define BUILD_EXEEXT $rB
+ define TARGET_EXEEXT $rH
+}
+
+########################################################################
+# @proj-dll-extension
+#
+# Works like proj-exe-extension except that it defines BUILD_DLLEXT
+# and TARGET_DLLEXT to one of (.so, ,dll, .dylib).
+#
+# Trivia: for .dylib files, the linker needs the -dynamiclib flag
+# instead of -shared.
+proc proj-dll-extension {} {
+ set inner {{key} {
+ switch -glob -- [get-define $key] {
+ *apple* {
+ return ".dylib"
+ }
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ return ".dll"
+ }
+ default {
+ return ".so"
+ }
+ }
+ }}
+ define BUILD_DLLEXT [apply $inner build]
+ define TARGET_DLLEXT [apply $inner host]
+}
+
+########################################################################
+# @proj-lib-extension
+#
+# Static-library counterpart of proj-dll-extension. Defines
+# BUILD_LIBEXT and TARGET_LIBEXT to the conventional static library
+# extension for the being-built-on resp. the target platform.
+proc proj-lib-extension {} {
+ set inner {{key} {
+ switch -glob -- [get-define $key] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ return ".a"
+ # ^^^ this was ".lib" until 2025-02-07. See
+ # https://sqlite.org/forum/forumpost/02db2d4240
+ }
+ default {
+ return ".a"
+ }
+ }
+ }}
+ define BUILD_LIBEXT [apply $inner build]
+ define TARGET_LIBEXT [apply $inner host]
+}
+
+########################################################################
+# @proj-file-extensions
+#
+# Calls all of the proj-*-extension functions.
+proc proj-file-extensions {} {
+ proj-exe-extension
+ proj-dll-extension
+ proj-lib-extension
+}
+
+########################################################################
+# @proj-affirm-files-exist ?-v? filename...
+#
+# Expects a list of file names. If any one of them does not exist in
+# the filesystem, it fails fatally with an informative message.
+# Returns the last file name it checks. If the first argument is -v
+# then it emits msg-checking/msg-result messages for each file.
+proc proj-affirm-files-exist {args} {
+ set rc ""
+ set verbose 0
+ if {[lindex $args 0] eq "-v"} {
+ set verbose 1
+ set args [lrange $args 1 end]
+ }
+ foreach f $args {
+ if {$verbose} { msg-checking "Looking for $f ... " }
+ if {![file exists $f]} {
+ user-error "not found: $f"
+ }
+ if {$verbose} { msg-result "" }
+ set rc $f
+ }
+ return rc
+}
+
+########################################################################
+# @proj-check-emsdk
+#
+# Emscripten is used for doing in-tree builds of web-based WASM stuff,
+# as opposed to WASI-based WASM or WASM binaries we import from other
+# places. This is only set up for Unix-style OSes and is untested
+# anywhere but Linux. Requires that the --with-emsdk flag be
+# registered with autosetup.
+#
+# It looks for the SDK in the location specified by --with-emsdk.
+# Values of "" or "auto" mean to check for the environment var EMSDK
+# (which gets set by the emsdk_env.sh script from the SDK) or that
+# same var passed to configure.
+#
+# If the given directory is found, it expects to find emsdk_env.sh in
+# that directory, as well as the emcc compiler somewhere under there.
+#
+# If the --with-emsdk[=DIR] flag is explicitly provided and the SDK is
+# not found then a fatal error is generated, otherwise failure to find
+# the SDK is not fatal.
+#
+# Defines the following:
+#
+# - HAVE_EMSDK = 0 or 1 (this function's return value)
+# - EMSDK_HOME = "" or top dir of the emsdk
+# - EMSDK_ENV_SH = "" or $EMSDK_HOME/emsdk_env.sh
+# - BIN_EMCC = "" or $EMSDK_HOME/upstream/emscripten/emcc
+#
+# Returns 1 if EMSDK_ENV_SH is found, else 0. If EMSDK_HOME is not empty
+# but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which
+# case we have to rely on the fact that sourcing $EMSDK_ENV_SH from a
+# shell will add emcc to the $PATH.
+proc proj-check-emsdk {} {
+ set emsdkHome [opt-val with-emsdk]
+ define EMSDK_HOME ""
+ define EMSDK_ENV_SH ""
+ define BIN_EMCC ""
+ set hadValue [llength $emsdkHome]
+ msg-checking "Emscripten SDK? "
+ if {$emsdkHome in {"" "auto"}} {
+ # Check the environment. $EMSDK gets set by sourcing emsdk_env.sh.
+ set emsdkHome [get-env EMSDK ""]
+ }
+ set rc 0
+ if {$emsdkHome ne ""} {
+ define EMSDK_HOME $emsdkHome
+ set emsdkEnv "$emsdkHome/emsdk_env.sh"
+ if {[file exists $emsdkEnv]} {
+ msg-result "$emsdkHome"
+ define EMSDK_ENV_SH $emsdkEnv
+ set rc 1
+ set emcc "$emsdkHome/upstream/emscripten/emcc"
+ if {[file exists $emcc]} {
+ define BIN_EMCC $emcc
+ }
+ } else {
+ msg-result "emsdk_env.sh not found in $emsdkHome"
+ }
+ } else {
+ msg-result "not found"
+ }
+ if {$hadValue && 0 == $rc} {
+ # Fail if it was explicitly requested but not found
+ proj-fatal "Cannot find the Emscripten SDK"
+ }
+ define HAVE_EMSDK $rc
+ return $rc
+}
+
+########################################################################
+# @proj-cc-check-Wl-flag ?flag ?args??
+#
+# Checks whether the given linker flag (and optional arguments) can be
+# passed from the compiler to the linker using one of these formats:
+#
+# - -Wl,flag[,arg1[,...argN]]
+# - -Wl,flag -Wl,arg1 ...-Wl,argN
+#
+# If so, that flag string is returned, else an empty string is
+# returned.
+proc proj-cc-check-Wl-flag {args} {
+ cc-with {-link 1} {
+ # Try -Wl,flag,...args
+ set fli "-Wl"
+ foreach f $args { append fli ",$f" }
+ if {[cc-check-flags $fli]} {
+ return $fli
+ }
+ # Try -Wl,flag -Wl,arg1 ...-Wl,argN
+ set fli ""
+ foreach f $args { append fli "-Wl,$f " }
+ if {[cc-check-flags $fli]} {
+ return [string trim $fli]
+ }
+ return ""
+ }
+}
+
+########################################################################
+# @proj-check-rpath
+#
+# Tries various approaches to handling the -rpath link-time
+# flag. Defines LDFLAGS_RPATH to that/those flag(s) or an empty
+# string. Returns 1 if it finds an option, else 0.
+#
+# By default, the rpath is set to $prefix/lib. However, if either of
+# --exec-prefix=... or --libdir=... are explicitly passed to
+# configure then [get-define libdir] is used (noting that it derives
+# from exec-prefix by default).
+proc proj-check-rpath {} {
+ if {[proj-opt-was-provided libdir]
+ || [proj-opt-was-provided exec-prefix]} {
+ set lp "[get-define libdir]"
+ } else {
+ set lp "[get-define prefix]/lib"
+ }
+ # If we _don't_ use cc-with {} here (to avoid updating the global
+ # CFLAGS or LIBS or whatever it is that cc-check-flags updates) then
+ # downstream tests may fail because the resulting rpath gets
+ # implicitly injected into them.
+ cc-with {-link 1} {
+ if {[cc-check-flags "-rpath $lp"]} {
+ define LDFLAGS_RPATH "-rpath $lp"
+ } else {
+ set wl [proj-cc-check-Wl-flag -rpath $lp]
+ if {"" eq $wl} {
+ set wl [proj-cc-check-Wl-flag -R$lp]
+ }
+ define LDFLAGS_RPATH $wl
+ }
+ }
+ expr {"" ne [get-define LDFLAGS_RPATH]}
+}
+
+########################################################################
+# @proj-check-soname ?libname?
+#
+# Checks whether CC supports the -Wl,soname,lib... flag. If so, it
+# returns 1 and defines LDFLAGS_SONAME_PREFIX to the flag's prefix, to
+# which the client would need to append "libwhatever.N". If not, it
+# returns 0 and defines LDFLAGS_SONAME_PREFIX to an empty string.
+#
+# The libname argument is only for purposes of running the flag
+# compatibility test, and is not included in the resulting
+# LDFLAGS_SONAME_PREFIX. It is provided so that clients may
+# potentially avoid some end-user confusion by using their own lib's
+# name here (which shows up in the "checking..." output).
+proc proj-check-soname {{libname "libfoo.so.0"}} {
+ cc-with {-link 1} {
+ if {[cc-check-flags "-Wl,-soname,${libname}"]} {
+ define LDFLAGS_SONAME_PREFIX "-Wl,-soname,"
+ return 1
+ } else {
+ define LDFLAGS_SONAME_PREFIX ""
+ return 0
+ }
+ }
+}
+
+########################################################################
+# Internal helper for proj-dump-defs-json. Expects to be passed a
+# [define] name and the variadic $args which are passed to
+# proj-dump-defs-json. If it finds a pattern match for the given
+# $name in the various $args, it returns the type flag for that $name,
+# e.g. "-str" or "-bare", else returns an empty string.
+proc proj-defs-type_ {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+########################################################################
+# Internal helper for proj-defs-format_: returns a JSON-ish quoted
+# form of the given string-type values. It only performs the most
+# basic of escaping. The input must not contain any control
+# characters.
+proc proj-quote-str_ {value} {
+ return \"[string map [list \\ \\\\ \" \\\"] $value]\"
+}
+
+########################################################################
+# An internal impl detail of proj-dump-defs-json. Requires a data
+# type specifier, as used by make-config-header, and a value. Returns
+# the formatted value or the value $::proj_(defs-skip) if the caller
+# should skip emitting that value.
+set proj_(defs-skip) "-proj-defs-format_ sentinel"
+proc proj-defs-format_ {type value} {
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ set value $::proj_(defs-skip)
+ }
+ -str {
+ set value [proj-quote-str_ $value]
+ }
+ -auto {
+ # Automatically determine the type
+ if {![string is integer -strict $value]} {
+ set value [proj-quote-str_ $value]
+ }
+ }
+ -array {
+ set ar {}
+ foreach v $value {
+ set v [proj-defs-format_ -auto $v]
+ if {$::proj_(defs-skip) ne $v} {
+ lappend ar $v
+ }
+ }
+ set value "\[ [join $ar {, }] \]"
+ }
+ "" {
+ set value $::proj_(defs-skip)
+ }
+ default {
+ proj-fatal "Unknown type in proj-dump-defs-json: $type"
+ }
+ }
+ return $value
+}
+
+########################################################################
+# This function works almost identically to autosetup's
+# make-config-header but emits its output in JSON form. It is not a
+# fully-functional JSON emitter, and will emit broken JSON for
+# complicated outputs, but should be sufficient for purposes of
+# emitting most configure vars (numbers and simple strings).
+#
+# In addition to the formatting flags supported by make-config-header,
+# it also supports:
+#
+# -array {patterns...}
+#
+# Any defines matching the given patterns will be treated as a list of
+# values, each of which will be formatted as if it were in an -auto {...}
+# set, and the define will be emitted to JSON in the form:
+#
+# "ITS_NAME": [ "value1", ...valueN ]
+#
+# Achtung: if a given -array pattern contains values which themselves
+# contains spaces...
+#
+# define-append foo {"-DFOO=bar baz" -DBAR="baz barre"}
+#
+# will lead to:
+#
+# ["-DFOO=bar baz", "-DBAR=\"baz", "barre\""]
+#
+# Neither is especially satisfactory (and the second is useless), and
+# handling of such values is subject to change if any such values ever
+# _really_ need to be processed by our source trees.
+proc proj-dump-defs-json {file args} {
+ file mkdir [file dirname $file]
+ set lines {}
+ lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+ foreach n [lsort [dict keys [all-defines]]] {
+ set type [proj-defs-type_ $n $args]
+ set value [proj-defs-format_ $type [get-define $n]]
+ if {$::proj_(defs-skip) ne $value} {
+ lappend lines "\"$n\": ${value}"
+ }
+ }
+ set buf {}
+ lappend buf [join $lines ",\n"]
+ write-if-changed $file $buf {
+ msg-result "Created $file"
+ }
+}
+
+########################################################################
+# @proj-xfer-option-aliases map
+#
+# Expects a list of pairs of configure flags which have been
+# registered with autosetup, in this form:
+#
+# { alias1 => canonical1
+# aliasN => canonicalN ... }
+#
+# The names must not have their leading -- part and must be in the
+# form which autosetup will expect for passing to [opt-val NAME] and
+# friends.
+#
+# Comment lines are permitted in the input.
+#
+# For each pair of ALIAS and CANONICAL, if --ALIAS is provided but
+# --CANONICAL is not, the value of the former is copied to the
+# latter. If --ALIAS is not provided, this is a no-op. If both have
+# explicitly been provided a fatal usage error is triggered.
+#
+# Motivation: autosetup enables "hidden aliases" in [options] lists,
+# and elides the aliases from --help output but does no further
+# handling of them. For example, when --alias is a hidden alias of
+# --canonical and a user passes --alias=X, [opt-val canonical] returns
+# no value. i.e. the script must check both [opt-val alias] and
+# [opt-val canonical]. The intent here is that this function be
+# passed such mappings immediately after [options] is called, to carry
+# over any values from hidden aliases into their canonical names, such
+# that [opt-value canonical] will return X if --alias=X is passed to
+# configure.
+proc proj-xfer-options-aliases {mapping} {
+ foreach {hidden - canonical} [proj-strip-hash-comments $mapping] {
+ if {[proj-opt-was-provided $hidden]} {
+ if {[proj-opt-was-provided $canonical]} {
+ proj-fatal "both --$canonical and its alias --$hidden were used. Use only one or the other."
+ } else {
+ proj-opt-set $canonical [opt-val $hidden]
+ }
+ }
+ }
+}
+
+########################################################################
+# Arguable/debatable...
+#
+# When _not_ cross-compiling and CC_FOR_BUILD is _not_ explicitly
+# specified, force CC_FOR_BUILD to be the same as CC, so that:
+#
+# ./configure CC=clang
+#
+# will use CC_FOR_BUILD=clang, instead of cc, for building in-tree
+# tools. This is based off of an email discussion and is thought to
+# be likely to cause less confusion than seeing 'cc' invocations
+# when when the user passes CC=clang.
+#
+# Sidebar: if we do this before the cc package is installed, it gets
+# reverted by that package. Ergo, the cc package init will tell the
+# user "Build C compiler...cc" shortly before we tell them otherwise.
+proc proj-redefine-cc-for-build {} {
+ if {![proj-is-cross-compiling]
+ && [get-define CC] ne [get-define CC_FOR_BUILD]
+ && "nope" eq [get-env CC_FOR_BUILD "nope"]} {
+ user-notice "Re-defining CC_FOR_BUILD to CC=[get-define CC]. To avoid this, explicitly pass CC_FOR_BUILD=..."
+ define CC_FOR_BUILD [get-define CC]
+ }
+}
+
+########################################################################
+# @proj-which-linenoise headerFile
+#
+# Attempts to determine whether the given linenoise header file is of
+# the "antirez" or "msteveb" flavor. It returns 2 for msteveb, else 1
+# (it does not validate that the header otherwise contains the
+# linenoise API).
+proc proj-which-linenoise {dotH} {
+ set srcHeader [proj-file-content $dotH]
+ if {[string match *userdata* $srcHeader]} {
+ return 2
+ } else {
+ return 1
+ }
+}
+
+########################################################################
+# @proj-remap-autoconf-dir-vars
+#
+# "Re-map" the autoconf-conventional --XYZdir flags into something
+# which is more easily overridable from a make invocation.
+#
+# Based off of notes in .
+#
+# Consider:
+#
+# $ ./configure --prefix=/foo
+# $ make install prefix=/blah
+#
+# In that make invocation, $(libdir) would, at make-time, normally be
+# hard-coded to /foo/lib, rather than /blah/lib. That happens because
+# autosetup exports conventional $prefix-based values for the numerous
+# autoconfig-compatible XYZdir vars at configure-time. What we would
+# normally want, however, is that --libdir derives from the make-time
+# $(prefix). The distinction between configure-time and make-time is
+# the significant factor there.
+#
+# This function attempts to reconcile those vars in such a way that
+# they will derive, at make-time, from $(prefix) in a conventional
+# manner unless they are explicitly overridden at configure-time, in
+# which case those overrides takes precedence.
+#
+# Each --XYZdir flag which is explicitly passed to configure is
+# exported as-is, as are those which default to some top-level system
+# directory, e.g. /etc or /var. All which derive from either $prefix
+# or $exec_prefix are exported in the form of a Makefile var
+# reference, e.g. libdir=${exec_prefix}/lib. Ergo, if
+# --exec-prefix=FOO is passed to configure, libdir will still derive,
+# at make-time, from whatever exec_prefix is passed to make, and will
+# use FOO if exec_prefix is not overridden at make-time. Without this
+# post-processing, libdir would be cemented in as FOO/lib at
+# configure-time, so could be tedious to override properly via a make
+# invocation.
+proc proj-remap-autoconf-dir-vars {} {
+ set prefix [get-define prefix]
+ set exec_prefix [get-define exec_prefix $prefix]
+ # The following var derefs must be formulated such that they are
+ # legal for use in (A) makefiles, (B) pkgconfig files, and (C) TCL's
+ # [subst] command. i.e. they must use the form ${X}.
+ foreach {flag makeVar makeDeref} {
+ exec-prefix exec_prefix ${prefix}
+ datadir datadir ${prefix}/share
+ mandir mandir ${datadir}/man
+ includedir includedir ${prefix}/include
+ bindir bindir ${exec_prefix}/bin
+ libdir libdir ${exec_prefix}/lib
+ sbindir sbindir ${exec_prefix}/sbin
+ sysconfdir sysconfdir /etc
+ sharedstatedir sharedstatedir ${prefix}/com
+ localstatedir localstatedir /var
+ runstatedir runstatedir /run
+ infodir infodir ${datadir}/info
+ libexecdir libexecdir ${exec_prefix}/libexec
+ } {
+ if {[proj-opt-was-provided $flag]} {
+ define $makeVar [join [opt-val $flag]]
+ } else {
+ define $makeVar [join $makeDeref]
+ }
+ # Maintenance reminder: the [join] call is to avoid {braces}
+ # around the output when someone passes in,
+ # e.g. --libdir=\${prefix}/foo/bar. The Debian package build
+ # script does that.
+ }
+}
+
+########################################################################
+# @proj-env-file flag ?default?
+#
+# If a file named .env-$flag exists, this function returns a
+# trimmed copy of its contents, else it returns $dflt. The intended
+# usage is that things like developer-specific CFLAGS preferences can
+# be stored in .env-CFLAGS.
+proc proj-env-file {flag {dflt ""}} {
+ set fn ".env-${flag}"
+ if {[file readable $fn]} {
+ return [proj-file-content -trim $fn]
+ }
+ return $dflt
+}
+
+########################################################################
+# @proj-get-env var ?default?
+#
+# Extracts the value of "environment" variable $var from the first of
+# the following places where it's defined:
+#
+# - Passed to configure as $var=...
+# - Exists as an environment variable
+# - A file named .env-$var (see [proj-env-file])
+#
+# If none of those are set, $dflt is returned.
+proc proj-get-env {var {dflt ""}} {
+ return [get-env $var [proj-env-file $var $dflt]]
+}
diff --git a/autosetup/sqlite-config.tcl b/autosetup/sqlite-config.tcl
new file mode 100644
index 0000000000..c09b8583f8
--- /dev/null
+++ b/autosetup/sqlite-config.tcl
@@ -0,0 +1,2097 @@
+# This file holds functions for autosetup which are specific to the
+# sqlite build tree. They are in this file, instead of auto.def, so
+# that they can be reused in the TEA sub-tree. This file requires
+# functions from proj.tcl.
+
+if {[string first " " $autosetup(srcdir)] != -1} {
+ user-error "The pathname of the source tree\
+ may not contain space characters"
+}
+if {[string first " " $autosetup(builddir)] != -1} {
+ user-error "The pathname of the build directory\
+ may not contain space characters"
+}
+
+use proj
+# We want this version info to be emitted up front, but we have to
+# 'use system' for --prefix=... to work. Ergo, this bit is up here
+# instead of in [sqlite-configure].
+define PACKAGE_VERSION [proj-file-content -trim $::autosetup(srcdir)/VERSION]
+if {"--help" ni $::argv} {
+ msg-result "Configuring SQLite version [get-define PACKAGE_VERSION]"
+}
+use system ; # Will output "Host System" and "Build System" lines
+if {"--help" ni $::argv} {
+ msg-result "Source dir = $::autosetup(srcdir)"
+ msg-result "Build dir = $::autosetup(builddir)"
+}
+
+#
+# Object for communicating config-time state across various
+# auto.def-related pieces.
+#
+array set sqliteConfig [proj-strip-hash-comments {
+ #
+ # Gets set to 1 when using jimsh for code generation. May affect
+ # later decisions.
+ use-jim-for-codegen 0
+ #
+ # Pass msg-debug=1 to configure to enable obnoxiously loud output
+ # from [msg-debug].
+ msg-debug-enabled 0
+ #
+ # Output file for --dump-defines. Intended only for build debugging
+ # and not part of the public build interface.
+ dump-defines-txt ./config.defines.txt
+ #
+ # If not empty then --dump-defines will dump not only
+ # (dump-defines-txt) but also a JSON file named after this option's
+ # value.
+ dump-defines-json ""
+}]
+
+#
+# Set to 1 when cross-compiling This value may be changed by certain
+# build options, so it's important that config code which checks for
+# cross-compilation uses this var instead of
+# [proj-is-cross-compiling].
+#
+set sqliteConfig(is-cross-compiling) [proj-is-cross-compiling]
+
+########################################################################
+# Processes all configure --flags for this build $buildMode must be
+# either "canonical" or "autoconf", and others may be added in the
+# future. After bootstrapping, $configScript is eval'd in the caller's
+# scope, then post-configuration finalization is run. $configScript is
+# intended to hold configure code which is specific to the given
+# $buildMode, with the caveat that _some_ build-specific code is
+# encapsulated in the configuration finalization step.
+proc sqlite-configure {buildMode configScript} {
+ set allBuildModes {canonical autoconf}
+ if {$buildMode ni $allBuildModes} {
+ user-error "Invalid build mode: $buildMode. Expecting one of: $allBuildModes"
+ }
+ set ::sqliteConfig(build-mode) $buildMode
+ ########################################################################
+ # A gentle introduction to flags handling in autosetup
+ #
+ # Reference: https://msteveb.github.io/autosetup/developer/
+ #
+ # All configure flags must be described in an 'options' call. The
+ # general syntax is:
+ #
+ # FLAG => {Help text}
+ #
+ # Where FLAG can have any of the following formats:
+ #
+ # boolopt => "a boolean option which defaults to disabled"
+ # boolopt2=1 => "a boolean option which defaults to enabled"
+ # stringopt: => "an option which takes an argument, e.g. --stringopt=value"
+ # stringopt2:=value => "an option where the argument is optional and defaults to 'value'"
+ # optalias booltopt3 => "a boolean with a hidden alias. --optalias is not shown in --help"
+ #
+ # Autosetup does no small amount of specialized handling for flags,
+ # especially booleans. Each bool-type --FLAG implicitly gets
+ # --enable-FLAG and --disable-FLAG forms. That can lead lead to some
+ # confusion when writing help text. For example:
+ #
+ # options { json=1 {Disable JSON functions} }
+ #
+ # The reason the help text says "disable" is because a boolean option
+ # which defaults to true is, in the --help text, rendered as:
+ #
+ # --disable-json Disable JSON functions
+ #
+ # Whereas a bool flag which defaults to false will instead render as:
+ #
+ # --enable-FLAG
+ #
+ # Non-boolean flags, in contrast, use the names specifically given to
+ # them in the [options] invocation. e.g. "with-tcl" is the --with-tcl
+ # flag.
+ #
+ # Fetching values for flags:
+ #
+ # booleans: use one of:
+ # - [opt-bool FLAG] is autosetup's built-in command for this, but we
+ # have some convenience variants:
+ # - [proj-opt-truthy FLAG]
+ # - [proj-opt-if-truthy FLAG {THEN} {ELSE}]
+ #
+ # Non-boolean (i.e. string) flags:
+ # - [opt-val FLAG ?default?]
+ # - [opt-str ...] - see the docs in ./autosetup/autosetup
+ #
+ # [proj-opt-was-provided] can be used to determine whether a flag was
+ # explicitly provided, which is often useful for distinguishing from
+ # the case of a default value.
+ ########################################################################
+ set allFlags {
+ # Structure: a list of M {Z} pairs, where M is a descriptive
+ # option group name and Z is a list of X Y pairs. X is a list of
+ # $buildMode name(s) to which the Y flags apply, or {*} to apply
+ # to all builds. Y is a {block} in the form expected by
+ # autosetup's [options] command. Each block which is applicable
+ # to $buildMode is appended to a new list before that list is
+ # passed on to [options]. The order of each Y and sub-Y is
+ # retained, which is significant for rendering of --help.
+
+ # When writing {help text blocks}, be aware that:
+ #
+ # A) autosetup formats them differently if the {block} starts with
+ # a newline: it starts left-aligned, directly under the --flag, and
+ # the rest of the block is pasted verbatim rather than
+ # pretty-printed.
+ #
+ # B) Vars and commands are NOT expanded, but we use a [subst] call
+ # below which will replace (only) var refs.
+
+ # Options for how to build the library
+ build-modes {
+ {*} {
+ shared=1 => {Disable build of shared libary}
+ static=1 => {Disable build of static library}
+ }
+ {canonical} {
+ amalgamation=1 => {Disable the amalgamation and instead build all files separately}
+ }
+ }
+
+ # Library-level features and defaults
+ lib-features {
+ {*} {
+ threadsafe=1 => {Disable mutexing}
+ with-tempstore:=no => {Use an in-RAM database for temporary tables: never,no,yes,always}
+ largefile=1
+ => {This legacy flag has no effect on the library but may influence
+ the contents of the generated sqlite_cfg.h}
+ # ^^^ It's not clear that this actually does anything, as
+ # HAVE_LFS is not checked anywhere in the .c/.h/.in files.
+ load-extension=1 => {Disable loading of external extensions}
+ math=1 => {Disable math functions}
+ json=1 => {Disable JSON functions}
+ memsys5 => {Enable MEMSYS5}
+ memsys3 => {Enable MEMSYS3}
+ fts3 => {Enable the FTS3 extension}
+ fts4 => {Enable the FTS4 extension}
+ fts5 => {Enable the FTS5 extension}
+ update-limit => {Enable the UPDATE/DELETE LIMIT clause}
+ geopoly => {Enable the GEOPOLY extension}
+ rtree => {Enable the RTREE extension}
+ session => {Enable the SESSION extension}
+ all => {Enable FTS4, FTS5, Geopoly, RTree, Sessions}
+ }
+ }
+
+ # Options for TCL support
+ tcl {
+ {canonical} {
+ with-tcl:DIR
+ => {Directory containing tclConfig.sh or a directory one level up from
+ that, from which we can derive a directory containing tclConfig.sh.
+ A dir name of "prefix" is equivalent to the directory specified by
+ the --prefix flag.}
+ with-tclsh:PATH
+ => {Full pathname of tclsh to use. It is used for (A) trying to find
+ tclConfig.sh and (B) all TCL-based code generation. Warning: if
+ its containing dir has multiple tclsh versions, it may select the
+ wrong tclConfig.sh!}
+ tcl=1
+ => {Disable components which require TCL, including all tests.
+ This tree requires TCL for code generation but can use the in-tree
+ copy of autosetup/jimsh0.c for that. The SQLite TCL extension and the
+ test code require a canonical tclsh.}
+ }
+ }
+
+ # Options for line-editing modes for the CLI shell
+ line-editing {
+ {*} {
+ readline=1
+ => {Disable readline support}
+ # --with-readline-lib is a backwards-compatible alias for
+ # --with-readline-ldflags
+ with-readline-lib:
+ with-readline-ldflags:=auto
+ => {Readline LDFLAGS, e.g. -lreadline -lncurses}
+ # --with-readline-inc is a backwards-compatible alias for
+ # --with-readline-cflags.
+ with-readline-inc:
+ with-readline-cflags:=auto
+ => {Readline CFLAGS, e.g. -I/path/to/includes}
+ with-readline-header:PATH
+ => {Full path to readline.h, from which --with-readline-cflags will be derived}
+ with-linenoise:DIR
+ => {Source directory for linenoise.c and linenoise.h}
+ editline=0
+ => {Enable BSD editline support}
+ }
+ }
+
+ # Options for ICU: International Components for Unicode
+ icu {
+ {*} {
+ with-icu-ldflags:LDFLAGS
+ => {Enable SQLITE_ENABLE_ICU and add the given linker flags for the
+ ICU libraries. e.g. on Ubuntu systems, try '-licui18n -licuuc -licudata'.}
+ with-icu-cflags:CFLAGS
+ => {Apply extra CFLAGS/CPPFLAGS necessary for building with ICU.
+ e.g. -I/usr/local/include}
+ with-icu-config:=auto
+ => {Enable SQLITE_ENABLE_ICU. Value must be one of: auto, pkg-config,
+ /path/to/icu-config}
+ icu-collations=0
+ => {Enable SQLITE_ENABLE_ICU_COLLATIONS. Requires --with-icu-ldflags=...
+ or --with-icu-config}
+ }
+ }
+
+ # Options for exotic/alternative build modes
+ alternative-builds {
+ {canonical} {
+ # Potential TODO: add --with-wasi-sdk support to the autoconf
+ # build
+ with-wasi-sdk:=/opt/wasi-sdk
+ => {Top-most dir of the wasi-sdk for a WASI build}
+
+ with-emsdk:=auto
+ => {Top-most dir of the Emscripten SDK installation.
+ Needed only by ext/wasm build. Default=EMSDK env var.}
+ }
+ }
+
+ # Options primarily for downstream packagers/package maintainers
+ packaging {
+ {autoconf} {
+ # --disable-static-shell: https://sqlite.org/forum/forumpost/cc219ee704
+ static-shell=1
+ => {Link the sqlite3 shell app against the DLL instead of embedding sqlite3.c}
+ }
+ {*} {
+ # A potential TODO without a current use case:
+ #rpath=1 => {Disable use of the rpath linker flag}
+ # soname: https://sqlite.org/src/forumpost/5a3b44f510df8ded
+ soname:=legacy
+ => {SONAME for libsqlite3.so. "none", or not using this flag, sets no
+ soname. "legacy" sets it to its historical value of
+ libsqlite3.so.0. A value matching the glob "libsqlite3.*" sets
+ it to that literal value. Any other value is assumed to be a
+ suffix which gets applied to "libsqlite3.so.",
+ e.g. --soname=9.10 equates to "libsqlite3.so.9.10".}
+ # dll-basename: https://sqlite.org/forum/forumpost/828fdfe904
+ dll-basename:=auto
+ => {Specifies the base name of the resulting DLL file.
+ If not provided, libsqlite3 is usually assumed but on some platforms
+ a platform-dependent default is used. On some platforms this flag
+ gets automatically enabled if it is not provided. Use "default" to
+ explicitly disable platform-dependent activation on such systems.}
+ # out-implib: https://sqlite.org/forum/forumpost/0c7fc097b2
+ out-implib:=auto
+ => {Enable use of --out-implib linker flag to generate an
+ "import library" for the DLL. The output's base name name is
+ specified by the value, with "auto" meaning to figure out a
+ name automatically. On some platforms this flag gets
+ automatically enabled if it is not provided. Use "none" to
+ explicitly disable this feature on such platforms.}
+ }
+ }
+
+ # Options mostly for sqlite's own development
+ developer {
+ {*} {
+ # Note that using the --debug/--enable-debug flag here
+ # requires patching autosetup/autosetup to rename its builtin
+ # --debug to --autosetup-debug. See details in
+ # autosetup/README.md#patching.
+ with-debug=0
+ debug=0
+ => {Enable debug build flags. This option will impact performance by
+ as much as 4x, as it includes large numbers of assert()s in
+ performance-critical loops. Never use --debug for production
+ builds.}
+ scanstatus
+ => {Enable the SQLITE_ENABLE_STMT_SCANSTATUS feature flag}
+ }
+ {canonical} {
+ dev
+ => {Enable dev-mode build: automatically enables certain other flags}
+ test-status
+ => {Enable status of tests}
+ gcov=0
+ => {Enable coverage testing using gcov}
+ linemacros
+ => {Enable #line macros in the amalgamation}
+ dynlink-tools
+ => {Dynamically link libsqlite3 to certain tools which normally statically embed it}
+ }
+ {*} {
+ dump-defines=0
+ => {Dump autosetup defines to $::sqliteConfig(dump-defines-txt)
+ (for build debugging)}
+ }
+ }
+ }; # $allOpts
+
+ # Filter allOpts to create the set of [options] legal for this build
+ set opts {}
+ foreach {group XY} [subst -nobackslashes -nocommands \
+ [proj-strip-hash-comments $allFlags]] {
+ foreach {X Y} $XY {
+ if { $buildMode in $X || "*" in $X } {
+ foreach y $Y {
+ lappend opts $y
+ }
+ }
+ }
+ }
+ #lappend opts "soname:=duplicateEntry => {x}"; #just testing
+ if {[catch {options $opts} msg xopts]} {
+ # Workaround for
+ # where [options] behaves oddly on _some_ TCL builds when it's
+ # called from deeper than the global scope.
+ dict incr xopts -level
+ return {*}$xopts $msg
+ }
+ # The following uplevel is largely cosmetic, the intent being to put
+ # the most-frequently-useful info at the top of the ./configure
+ # output, but also avoiding outputing it if --help is used.
+ uplevel 1 {
+ use cc cc-db cc-shared cc-lib pkg-config
+ }
+ sqlite-post-options-init
+ uplevel 1 $configScript
+ sqlite-configure-finalize
+}; # sqlite-configure
+
+########################################################################
+# Performs late-stage config steps common to both the canonical and
+# autoconf bundle builds.
+proc sqlite-configure-finalize {} {
+ set buildMode $::sqliteConfig(build-mode)
+ set isCanonical [expr {$buildMode eq "canonical"}]
+ set isAutoconf [expr {$buildMode eq "autoconf"}]
+
+ define HAVE_LFS 0
+ if {[opt-bool largefile]} {
+ #
+ # Insofar as we can determine HAVE_LFS has no effect on the
+ # library. Perhaps it did back in the early 2000's. The
+ # --enable/disable-largefile flag is retained because it's
+ # harmless, but it doesn't do anything useful. It does have
+ # visible side-effects, though: the generated sqlite_cfg.h may (or
+ # may not) define HAVE_LFS.
+ #
+ cc-check-lfs
+ }
+
+ if {$isCanonical} {
+ if {![opt-bool static]} {
+ proj-indented-notice {
+ NOTICE: static lib build may be implicitly re-activated by
+ other components, e.g. some test apps.
+ }
+ }
+ } else {
+ proj-assert { $isAutoconf } "Invalid build mode"
+ proj-define-for-opt static-shell ENABLE_STATIC_SHELL \
+ "Link library statically into the CLI shell?"
+ if {![opt-bool shared] && ![opt-bool static-shell]} {
+ proj-opt-set shared 1
+ proj-indented-notice {
+ NOTICE: ignoring --disable-shared because --disable-static-shell
+ was specified.
+ }
+ }
+ }
+ proj-define-for-opt shared ENABLE_LIB_SHARED "Build shared library?"
+ proj-define-for-opt static ENABLE_LIB_STATIC "Build static library?"
+
+ sqlite-handle-debug
+ sqlite-handle-rpath
+ sqlite-handle-soname
+ sqlite-handle-threadsafe
+ sqlite-handle-tempstore
+ sqlite-handle-line-editing
+ sqlite-handle-load-extension
+ sqlite-handle-math
+ sqlite-handle-icu
+ sqlite-handle-env-quirks
+ sqlite-process-dot-in-files
+ sqlite-post-config-validation
+ sqlite-dump-defines
+}; # sqlite-configure-finalize
+
+########################################################################
+# Runs some common initialization which must happen immediately after
+# autosetup's [options] function is called. This is also a convenient
+# place to put some generic pieces common to both the canonical
+# top-level build and the "autoconf" build, but it's not intended to
+# be a catch-all dumping ground for such.
+proc sqlite-post-options-init {} {
+ define PACKAGE_NAME "sqlite"
+ define PACKAGE_URL {https://sqlite.org}
+ define PACKAGE_BUGREPORT [get-define PACKAGE_URL]/forum
+ define PACKAGE_STRING "[get-define PACKAGE_NAME] [get-define PACKAGE_VERSION]"
+ #
+ # Carry values from hidden --flag aliases over to their canonical
+ # flag forms. This list must include only options which are common
+ # to both the top-level auto.def and autoconf/auto.def.
+ #
+ proj-xfer-options-aliases {
+ with-readline-inc => with-readline-cflags
+ with-readline-lib => with-readline-ldflags
+ with-debug => debug
+ }
+ sqlite-autoreconfig
+ proj-file-extensions
+ if {".exe" eq [get-define TARGET_EXEEXT]} {
+ define SQLITE_OS_UNIX 0
+ define SQLITE_OS_WIN 1
+ } else {
+ define SQLITE_OS_UNIX 1
+ define SQLITE_OS_WIN 0
+ }
+ set ::sqliteConfig(msg-debug-enabled) [proj-val-truthy [get-env msg-debug 0]]
+ sqlite-setup-default-cflags
+}
+
+########################################################################
+# Internal config-time debugging output routine. It generates no
+# output unless msg-debug=1 is passed to the configure script.
+proc msg-debug {msg} {
+ if {$::sqliteConfig(msg-debug-enabled)} {
+ puts stderr [proj-bold "** DEBUG: $msg"]
+ }
+}
+
+########################################################################
+# Sets up the SQLITE_AUTORECONFIG define.
+proc sqlite-autoreconfig {} {
+ #
+ # SQLITE_AUTORECONFIG contains make target rules for re-running the
+ # configure script with the same arguments it was initially invoked
+ # with. This can be used to automatically reconfigure
+ #
+ set squote {{arg} {
+ # Wrap $arg in single-quotes if it looks like it might need that
+ # to avoid mis-handling as a shell argument. We assume that $arg
+ # will never contain any single-quote characters.
+ if {[string match {*[ &;$*"]*} $arg]} { return '$arg' }
+ return $arg
+ }}
+ define-append SQLITE_AUTORECONFIG cd [apply $squote $::autosetup(builddir)] \
+ && [apply $squote $::autosetup(srcdir)/configure]
+ #{*}$::autosetup(argv) breaks with --flag='val with spaces', so...
+ foreach arg $::autosetup(argv) {
+ define-append SQLITE_AUTORECONFIG [apply $squote $arg]
+ }
+}
+
+define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
+define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
+########################################################################
+# Adds $args, if not empty, to OPT_FEATURE_FLAGS. If the first arg is
+# -shell then it strips that arg and passes the remaining args the
+# sqlite-add-shell-opt in addition to adding them to
+# OPT_FEATURE_FLAGS.
+proc sqlite-add-feature-flag {args} {
+ set shell ""
+ if {"-shell" eq [lindex $args 0]} {
+ set args [lassign $args shell]
+ }
+ if {"" ne $args} {
+ if {"" ne $shell} {
+ sqlite-add-shell-opt {*}$args
+ }
+ define-append OPT_FEATURE_FLAGS {*}$args
+ }
+}
+# Appends $args, if not empty, to OPT_SHELL.
+proc sqlite-add-shell-opt {args} {
+ if {"" ne $args} {
+ define-append OPT_SHELL {*}$args
+ }
+}
+
+########################################################################
+# Check for log(3) in libm and die with an error if it is not
+# found. $featureName should be the feature name which requires that
+# function (it's used only in error messages). defines LDFLAGS_MATH to
+# the required linker flags (which may be empty even if the math APIs
+# are found, depending on the OS).
+proc sqlite-affirm-have-math {featureName} {
+ if {"" eq [get-define LDFLAGS_MATH ""]} {
+ if {![msg-quiet proj-check-function-in-lib log m]} {
+ user-error "Missing math APIs for $featureName"
+ }
+ define LDFLAGS_MATH [get-define lib_log ""]
+ undefine lib_log
+ }
+}
+
+########################################################################
+# Run checks for required binaries, like ld and ar. In the canonical
+# build this must come before [sqlite-handle-wasi-sdk].
+proc sqlite-check-common-bins {} {
+ cc-check-tools ld ar ; # must come before [sqlite-handle-wasi-sdk]
+ if {"" eq [proj-bin-define install]} {
+ proj-warn "Cannot find install binary, so 'make install' will not work."
+ define BIN_INSTALL false
+ }
+}
+
+########################################################################
+# Run checks for system-level includes and libs which are common to
+# both the canonical build and the "autoconf" bundle.
+proc sqlite-check-common-system-deps {} {
+ #
+ # Check for needed/wanted data types
+ cc-with {-includes stdint.h} \
+ {cc-check-types int8_t int16_t int32_t int64_t intptr_t \
+ uint8_t uint16_t uint32_t uint64_t uintptr_t}
+
+ #
+ # Check for needed/wanted functions
+ cc-check-functions gmtime_r isnan localtime_r localtime_s \
+ malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64
+
+ set ldrt ""
+ # Collapse funcs from librt into LDFLAGS_RT.
+ # Some systems (ex: SunOS) require -lrt in order to use nanosleep
+ foreach func {fdatasync nanosleep} {
+ if {[proj-check-function-in-lib $func rt]} {
+ lappend ldrt [get-define lib_${func}]
+ }
+ }
+ define LDFLAGS_RT [join [lsort -unique $ldrt] ""]
+
+ #
+ # Check for needed/wanted headers
+ cc-check-includes \
+ sys/types.h sys/stat.h dlfcn.h unistd.h \
+ stdlib.h malloc.h memory.h \
+ string.h strings.h \
+ inttypes.h
+
+ if {[cc-check-includes zlib.h] && [proj-check-function-in-lib deflate z]} {
+ # TODO? port over the more sophisticated zlib search from the fossil auto.def
+ define HAVE_ZLIB 1
+ define LDFLAGS_ZLIB -lz
+ sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
+ } else {
+ define HAVE_ZLIB 0
+ define LDFLAGS_ZLIB ""
+ }
+}
+
+proc sqlite-setup-default-cflags {} {
+ ########################################################################
+ # We differentiate between two C compilers: the one used for binaries
+ # which are to run on the build system (in autosetup it's called
+ # CC_FOR_BUILD and in Makefile.in it's $(B.cc)) and the one used for
+ # compiling binaries for the target system (CC a.k.a. $(T.cc)).
+ # Normally they're the same, but they will differ when
+ # cross-compiling.
+ #
+ # When cross-compiling we default to not using the -g flag, based on a
+ # /chat discussion prompted by
+ # https://sqlite.org/forum/forumpost/9a67df63eda9925c
+ set defaultCFlags {-O2}
+ if {!$::sqliteConfig(is-cross-compiling)} {
+ lappend defaultCFlags -g
+ }
+ define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
+ # BUILD_CFLAGS is the CFLAGS for CC_FOR_BUILD.
+ define BUILD_CFLAGS [proj-get-env BUILD_CFLAGS {-g}]
+
+ # Copy all CFLAGS and CPPFLAGS entries matching -DSQLITE_OMIT* and
+ # -DSQLITE_ENABLE* to OPT_FEATURE_FLAGS. This behavior is derived
+ # from the legacy build and was missing the 3.48.0 release (the
+ # initial Autosetup port).
+ # https://sqlite.org/forum/forumpost/9801e54665afd728
+ #
+ # Handling of CPPFLAGS, as well as removing ENABLE/OMIT from
+ # CFLAGS/CPPFLAGS, was missing in the 3.49.0 release as well.
+ #
+ # If any configure flags for features are in conflict with
+ # CFLAGS/CPPFLAGS-specified feature flags, all bets are off. There
+ # are no guarantees about which one will take precedence.
+ foreach flagDef {CFLAGS CPPFLAGS} {
+ set tmp ""
+ foreach cf [get-define $flagDef ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {
+ sqlite-add-feature-flag $cf
+ }
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define $flagDef $tmp
+ }
+
+ # Strip all SQLITE_ENABLE/OMIT flags from BUILD_CFLAGS,
+ # for compatibility with the legacy build.
+ set tmp ""
+ foreach cf [get-define BUILD_CFLAGS ""] {
+ switch -glob -- $cf {
+ -DSQLITE_OMIT* -
+ -DSQLITE_ENABLE* {}
+ default {
+ lappend tmp $cf
+ }
+ }
+ }
+ define BUILD_CFLAGS $tmp
+}
+
+########################################################################
+# Handle various SQLITE_ENABLE_... feature flags.
+proc sqlite-handle-common-feature-flags {} {
+ msg-result "Feature flags..."
+ if {"tcl-extension" eq $::sqliteConfig(build-mode)} {
+ set allFlagEnables {fts3 fts4 fts5 rtree geopoly}
+ } else {
+ set allFlagEnables {fts4 fts5 rtree rtree geopoly session}
+ }
+ if {![opt-bool all]} {
+ # Special handling for --disable-all
+ foreach flag $allFlagEnables {
+ if {![proj-opt-was-provided $flag]} {
+ proj-opt-set $flag 0
+ }
+ }
+ }
+ foreach {boolFlag featureFlag ifSetEvalThis} [proj-strip-hash-comments {
+ all {} {
+ # The 'all' option must be first in this list. This impl makes
+ # an effort to only apply flags which the user did not already
+ # apply, so that combinations like (--all --disable-geopoly)
+ # will indeed disable geopoly. There are corner cases where
+ # flags which depend on each other will behave in non-intuitive
+ # ways:
+ #
+ # --all --disable-rtree
+ #
+ # Will NOT disable geopoly, though geopoly depends on rtree.
+ # The --geopoly flag, though, will automatically re-enable
+ # --rtree, so --disable-rtree won't actually disable anything in
+ # that case.
+ foreach k $allFlagEnables {
+ if {![proj-opt-was-provided $k]} {
+ proj-opt-set $k 1
+ }
+ }
+ }
+ fts3 -DSQLITE_ENABLE_FTS3 {sqlite-affirm-have-math fts3}
+ fts4 -DSQLITE_ENABLE_FTS4 {sqlite-affirm-have-math fts4}
+ fts5 -DSQLITE_ENABLE_FTS5 {sqlite-affirm-have-math fts5}
+ geopoly -DSQLITE_ENABLE_GEOPOLY {proj-opt-set rtree}
+ rtree -DSQLITE_ENABLE_RTREE {}
+ session {-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK} {}
+ update-limit -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT {}
+ memsys5 -DSQLITE_ENABLE_MEMSYS5 {}
+ memsys3 {} {
+ if {[opt-bool memsys5]} {
+ proj-warn "not enabling memsys3 because memsys5 is enabled."
+ expr 0
+ } else {
+ sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
+ }
+ }
+ scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
+ }] {
+ if {$boolFlag ni $::autosetup(options)} {
+ # Skip flags which are in the canonical build but not
+ # the autoconf bundle.
+ continue
+ }
+ proj-if-opt-truthy $boolFlag {
+ sqlite-add-feature-flag $featureFlag
+ if {0 != [eval $ifSetEvalThis] && "all" ne $boolFlag} {
+ msg-result " + $boolFlag"
+ }
+ } {
+ if {"all" ne $boolFlag} {
+ msg-result " - $boolFlag"
+ }
+ }
+ }
+ ########################################################################
+ # Invert the above loop's logic for some SQLITE_OMIT_... cases. If
+ # config option $boolFlag is false, [sqlite-add-feature-flag
+ # $featureFlag], where $featureFlag is intended to be
+ # -DSQLITE_OMIT_...
+ foreach {boolFlag featureFlag} {
+ json -DSQLITE_OMIT_JSON
+ } {
+ if {[proj-opt-truthy $boolFlag]} {
+ msg-result " + $boolFlag"
+ } else {
+ sqlite-add-feature-flag $featureFlag
+ msg-result " - $boolFlag"
+ }
+ }
+
+}
+
+#########################################################################
+# Remove duplicates from the final feature flag sets and show them to
+# the user.
+proc sqlite-finalize-feature-flags {} {
+ set oFF [get-define OPT_FEATURE_FLAGS]
+ if {"" ne $oFF} {
+ define OPT_FEATURE_FLAGS [lsort -unique $oFF]
+ msg-result "Library feature flags: [get-define OPT_FEATURE_FLAGS]"
+ }
+ set oFF [get-define OPT_SHELL]
+ if {"" ne $oFF} {
+ define OPT_SHELL [lsort -unique $oFF]
+ msg-result "Shell options: [get-define OPT_SHELL]"
+ }
+}
+
+########################################################################
+# Checks for the --debug flag, defining SQLITE_DEBUG to 1 if it is
+# true. TARGET_DEBUG gets defined either way, with content depending
+# on whether --debug is true or false.
+proc sqlite-handle-debug {} {
+ msg-checking "SQLITE_DEBUG build? "
+ proj-if-opt-truthy debug {
+ define SQLITE_DEBUG 1
+ define TARGET_DEBUG {-g -DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall}
+ proj-opt-set memsys5
+ msg-result yes
+ } {
+ define TARGET_DEBUG {-DNDEBUG}
+ msg-result no
+ }
+}
+
+########################################################################
+# "soname" for libsqlite3.so. See discussion at:
+# https://sqlite.org/src/forumpost/5a3b44f510df8ded
+proc sqlite-handle-soname {} {
+ define LDFLAGS_LIBSQLITE3_SONAME ""
+ if {[proj-opt-was-provided soname]} {
+ set soname [join [opt-val soname] ""]
+ } else {
+ # Enabling soname breaks linking for the --dynlink-tools feature,
+ # and this project has no direct use for soname, so default to
+ # none. Package maintainers, on the other hand, like to have an
+ # soname.
+ set soname none
+ }
+ switch -exact -- $soname {
+ none - "" { return 0 }
+ legacy { set soname libsqlite3.so.0 }
+ default {
+ if {[string match libsqlite3.* $soname]} {
+ # use it as-is
+ } else {
+ # Assume it's a suffix
+ set soname "libsqlite3.so.${soname}"
+ }
+ }
+ }
+ msg-debug "soname=$soname"
+ if {[proj-check-soname $soname]} {
+ define LDFLAGS_LIBSQLITE3_SONAME [get-define LDFLAGS_SONAME_PREFIX]$soname
+ msg-result "Setting SONAME using: [get-define LDFLAGS_LIBSQLITE3_SONAME]"
+ } elseif {[proj-opt-was-provided soname]} {
+ # --soname was explicitly requested but not available, so fail fatally
+ proj-fatal "This environment does not support SONAME."
+ } else {
+ # --soname was not explicitly requested but not available, so just warn
+ msg-result "This environment does not support SONAME."
+ }
+}
+
+########################################################################
+# If --enable-threadsafe is set, this adds -DSQLITE_THREADSAFE=1 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to the linker flags
+# needed for linking pthread (possibly an empty string). If
+# --enable-threadsafe is not set, adds -DSQLITE_THREADSAFE=0 to
+# OPT_FEATURE_FLAGS and sets LDFLAGS_PTHREAD to an empty string.
+proc sqlite-handle-threadsafe {} {
+ msg-checking "Support threadsafe operation? "
+ define LDFLAGS_PTHREAD ""
+ set enable 0
+ proj-if-opt-truthy threadsafe {
+ msg-result "Checking for libs..."
+ if {[proj-check-function-in-lib pthread_create pthread]
+ && [proj-check-function-in-lib pthread_mutexattr_init pthread]} {
+ set enable 1
+ define LDFLAGS_PTHREAD [get-define lib_pthread_create]
+ undefine lib_pthread_create
+ undefine lib_pthread_mutexattr_init
+ } elseif {[proj-opt-was-provided threadsafe]} {
+ user-error "Missing required pthread libraries. Use --disable-threadsafe to disable this check."
+ } else {
+ msg-result "pthread support not detected"
+ }
+ # Recall that LDFLAGS_PTHREAD might be empty even if pthreads if
+ # found because it's in -lc on some platforms.
+ } {
+ msg-result "Disabled using --disable-threadsafe"
+ }
+ sqlite-add-feature-flag -DSQLITE_THREADSAFE=${enable}
+ return $enable
+}
+
+########################################################################
+# Handles the --with-tempstore flag.
+#
+# The test fixture likes to set SQLITE_TEMP_STORE on its own, so do
+# not set that feature flag unless it was explicitly provided to the
+# configure script.
+proc sqlite-handle-tempstore {} {
+ if {[proj-opt-was-provided with-tempstore]} {
+ set ts [opt-val with-tempstore no]
+ set tsn 1
+ msg-checking "Use an in-RAM database for temporary tables? "
+ switch -exact -- $ts {
+ never { set tsn 0 }
+ no { set tsn 1 }
+ yes { set tsn 2 }
+ always { set tsn 3 }
+ default {
+ user-error "Invalid --with-tempstore value '$ts'. Use one of: never, no, yes, always"
+ }
+ }
+ msg-result $ts
+ sqlite-add-feature-flag -DSQLITE_TEMP_STORE=$tsn
+ }
+}
+
+########################################################################
+# Check for the Emscripten SDK for building the web-based wasm
+# components. The core lib and tools do not require this but ext/wasm
+# does. Most of the work is done via [proj-check-emsdk], then this
+# function adds the following defines:
+#
+# - EMCC_WRAPPER = "" or top-srcdir/tool/emcc.sh
+# - BIN_WASM_OPT = "" or path to wasm-opt
+# - BIN_WASM_STRIP = "" or path to wasm-strip
+#
+# Noting that:
+#
+# 1) Not finding the SDK is not fatal at this level, nor is failure to
+# find one of the related binaries.
+#
+# 2) wasm-strip is part of the wabt package:
+#
+# https://github.com/WebAssembly/wabt
+#
+# and this project requires it for production-mode builds but not dev
+# builds.
+#
+proc sqlite-handle-emsdk {} {
+ define EMCC_WRAPPER ""
+ define BIN_WASM_STRIP ""
+ define BIN_WASM_OPT ""
+ set srcdir $::autosetup(srcdir)
+ if {$srcdir ne $::autosetup(builddir)} {
+ # The EMSDK pieces require writing to the original source tree
+ # even when doing an out-of-tree build. The ext/wasm pieces do not
+ # support an out-of-tree build so we treat that case as if EMSDK
+ # were not found.
+ msg-result "Out-of tree build: not checking for EMSDK."
+ return
+ }
+ set emccSh $srcdir/tool/emcc.sh
+ set extWasmConfig $srcdir/ext/wasm/config.make
+ if {![get-define HAVE_WASI_SDK] && [proj-check-emsdk]} {
+ define EMCC_WRAPPER $emccSh
+ set emsdkHome [get-define EMSDK_HOME ""]
+ proj-assert {"" ne $emsdkHome}
+ #define EMCC_WRAPPER ""; # just for testing
+ proj-bin-define wasm-strip
+ proj-bin-define bash; # ext/wasm/GNUmakefile requires bash
+ if {[file-isexec $emsdkHome/upstream/bin/wasm-opt]} {
+ define BIN_WASM_OPT $emsdkHome/upstream/bin/wasm-opt
+ } else {
+ # Maybe there's a copy in the path?
+ proj-bin-define wasm-opt BIN_WASM_OPT
+ }
+ proj-make-from-dot-in $emccSh $extWasmConfig
+ catch {exec chmod u+x $emccSh}
+ } else {
+ define EMCC_WRAPPER ""
+ file delete -force -- $emccSh $extWasmConfig
+ }
+}
+
+########################################################################
+# Internal helper for [sqlite-check-line-editing]. Returns a list of
+# potential locations under which readline.h might be found.
+proc sqlite-get-readline-dir-list {} {
+ # Historical note: the dirs list, except for the inclusion of
+ # $prefix and some platform-specific dirs, originates from the
+ # legacy configure script
+ set dirs [list [get-define prefix]]
+ switch -glob -- [get-define host] {
+ *-linux-android {
+ # Possibly termux
+ lappend dirs /data/data/com.termux/files/usr
+ }
+ *-mingw32 {
+ lappend dirs /mingw32 /mingw
+ }
+ *-mingw64 {
+ lappend dirs /mingw64 /mingw
+ }
+ }
+ lappend dirs /usr /usr/local /usr/local/readline /usr/contrib
+ set rv {}
+ foreach d $dirs {
+ if {[file isdir $d]} {lappend rv $d}
+ }
+ #msg-debug "sqlite-get-readline-dir-list dirs=$rv"
+ return $rv
+}
+
+########################################################################
+# sqlite-check-line-editing jumps through proverbial hoops to try to
+# find a working line-editing library, setting:
+#
+# - HAVE_READLINE to 0 or 1
+# - HAVE_LINENOISE to 0, 1, or 2
+# - HAVE_EDITLINE to 0 or 1
+#
+# Only one of ^^^ those will be set to non-0.
+#
+# - LDFLAGS_READLINE = linker flags or empty string
+#
+# - CFLAGS_READLINE = compilation flags for clients or empty string.
+#
+# Note that LDFLAGS_READLINE and CFLAGS_READLINE may refer to
+# linenoise or editline, not necessarily libreadline. In some cases
+# it will set HAVE_READLINE=1 when it's really using editline, for
+# reasons described in this function's comments.
+#
+# Returns a string describing which line-editing approach to use, or
+# "none" if no option is available.
+#
+# Order of checks:
+#
+# 1) --with-linenoise trumps all others and skips all of the
+# complexities involved with the remaining options.
+#
+# 2) --editline trumps --readline
+#
+# 3) --disable-readline trumps --readline
+#
+# 4) Default to automatic search for optional readline
+#
+# 5) Try to find readline or editline. If it's not found AND the
+# corresponding --FEATURE flag was explicitly given, fail fatally,
+# else fail silently.
+proc sqlite-check-line-editing {} {
+ msg-result "Checking for line-editing capability..."
+ define HAVE_READLINE 0
+ define HAVE_LINENOISE 0
+ define HAVE_EDITLINE 0
+ define LDFLAGS_READLINE ""
+ define CFLAGS_READLINE ""
+ set failIfNotFound 0 ; # Gets set to 1 for explicit --FEATURE requests
+ # so that we know whether to fail fatally or not
+ # if the library is not found.
+ set libsForReadline {readline edit} ; # -l names to check for readline().
+ # The libedit check changes this.
+ set editLibName "readline" ; # "readline" or "editline"
+ set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
+ set dirLn [opt-val with-linenoise]
+ if {"" ne $dirLn} {
+ # Use linenoise from a copy of its sources (not a library)...
+ if {![file isdir $dirLn]} {
+ proj-fatal "--with-linenoise value is not a directory"
+ }
+ set lnH $dirLn/linenoise.h
+ if {![file exists $lnH] } {
+ proj-fatal "Cannot find linenoise.h in $dirLn"
+ }
+ set lnC ""
+ set lnCOpts {linenoise-ship.c linenoise.c}
+ foreach f $lnCOpts {
+ if {[file exists $dirLn/$f]} {
+ set lnC $dirLn/$f
+ break;
+ }
+ }
+ if {"" eq $lnC} {
+ proj-fatal "Cannot find any of $lnCOpts in $dirLn"
+ }
+ set flavor ""
+ set lnVal [proj-which-linenoise $lnH]
+ switch -- $lnVal {
+ 1 { set flavor "antirez" }
+ 2 { set flavor "msteveb" }
+ default {
+ proj-fatal "Cannot determine the flavor of linenoise from $lnH"
+ }
+ }
+ define CFLAGS_READLINE "-I$dirLn $lnC"
+ define HAVE_LINENOISE $lnVal
+ sqlite-add-shell-opt -DHAVE_LINENOISE=$lnVal
+ if {$::sqliteConfig(use-jim-for-codegen) && 2 == $lnVal} {
+ define-append CFLAGS_JIMSH -DUSE_LINENOISE [get-define CFLAGS_READLINE]
+ user-notice "Adding linenoise support to jimsh."
+ }
+ return "linenoise ($flavor)"
+ } elseif {[opt-bool editline]} {
+ # libedit mimics libreadline and on some systems does not have its
+ # own header installed (instead, that of libreadline is used).
+ #
+ # shell.c historically expects HAVE_EDITLINE to be set for
+ # libedit, but it then expects to see , which
+ # some system's don't actually have despite having libedit. If we
+ # end up finding below, we will use
+ # -DHAVE_EDITLINE=1, else we will use -DHAVE_READLINE=1. In either
+ # case, we will link against libedit.
+ set failIfNotFound 1
+ set libsForReadline {edit}
+ set editLibName editline
+ } elseif {![opt-bool readline]} {
+ msg-result "Readline support explicitly disabled with --disable-readline"
+ return "none"
+ } elseif {[proj-opt-was-provided readline]} {
+ # If an explicit --[enable-]readline was used, fail if it's not
+ # found, else treat the feature as optional.
+ set failIfNotFound 1
+ }
+
+ # Transform with-readline-header=X to with-readline-cflags=-I...
+ set v [opt-val with-readline-header]
+ proj-opt-set with-readline-header ""
+ if {"" ne $v} {
+ if {"auto" eq $v} {
+ proj-opt-set with-readline-cflags auto
+ } else {
+ set v [file dirname $v]
+ if {[string match */readline $v]} {
+ # Special case: if the path includes .../readline/readline.h,
+ # set the -I to one dir up from that because our sources
+ # #include or .
+ set v [file dirname $v]
+ }
+ proj-opt-set with-readline-cflags "-I$v"
+ }
+ }
+
+ # Look for readline.h
+ set rlInc [opt-val with-readline-cflags auto]
+ if {"auto" eq $rlInc} {
+ set rlInc ""
+ if {$::sqliteConfig(is-cross-compiling)} {
+ # ^^^ this check is derived from the legacy configure script.
+ proj-warn "Skipping check for readline.h because we're cross-compiling."
+ } else {
+ set dirs [sqlite-get-readline-dir-list]
+ set subdirs "include/$editLibName"
+ if {"editline" eq $editLibName} {
+ lappend subdirs include/readline
+ # ^^^ editline, on some systems, does not have its own header,
+ # and uses libreadline's header.
+ }
+ lappend subdirs include
+ set rlInc [proj-search-for-header-dir readline.h \
+ -dirs $dirs -subdirs $subdirs]
+ if {"" ne $rlInc} {
+ if {[string match */readline $rlInc]} {
+ set rlInc [file dirname $rlInc]; # CLI shell: #include
+ } elseif {[string match */editline $rlInc]} {
+ set editLibDef HAVE_EDITLINE
+ set rlInc [file dirname $rlInc]; # CLI shell: #include
+ }
+ set rlInc "-I${rlInc}"
+ }
+ }
+ } elseif {"" ne $rlInc && ![string match *-I* $rlInc]} {
+ proj-fatal "Argument to --with-readline-cflags is intended to be CFLAGS and contain -I..."
+ }
+
+ # If readline.h was found/specified, look for lib(readline|edit)...
+ #
+ # This is not quite straightforward because both libreadline and
+ # libedit typically require some other library which (according to
+ # legacy autotools-generated tests) provides tgetent(3). On some
+ # systems that's built into libreadline/edit, on some (most?) its in
+ # lib[n]curses, and on some it's in libtermcap.
+ set rlLib ""
+ if {"" ne $rlInc} {
+ set rlLib [opt-val with-readline-ldflags]
+ if {$rlLib eq "auto" || $rlLib eq ""} {
+ set rlLib ""
+ set libTerm ""
+ if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
+ # ^^^ that libs list comes from the legacy configure script ^^^
+ set libTerm [get-define lib_tgetent]
+ undefine lib_tgetent
+ }
+ if {$editLibName eq $libTerm} {
+ set rlLib $libTerm
+ } elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
+ set rlLib [get-define lib_readline]
+ lappend rlLib $libTerm
+ undefine lib_readline
+ }
+ }
+ }
+
+ # If we found a library, configure the build to use it...
+ if {"" ne $rlLib} {
+ if {"editline" eq $editLibName && "HAVE_READLINE" eq $editLibDef} {
+ # Alert the user that, despite outward appearances, we won't be
+ # linking to the GPL'd libreadline. Presumably that distinction is
+ # significant for those using --editline.
+ proj-indented-notice {
+ NOTE: the local libedit uses so we
+ will compile with -DHAVE_READLINE=1 but will link with
+ libedit.
+ }
+ }
+ set rlLib [join $rlLib]
+ set rlInc [join $rlInc]
+ define LDFLAGS_READLINE $rlLib
+ define CFLAGS_READLINE $rlInc
+ proj-assert {$editLibDef in {HAVE_READLINE HAVE_EDITLINE}}
+ proj-assert {$editLibName in {readline editline}}
+ sqlite-add-shell-opt -D${editLibDef}=1
+ msg-result "Using $editLibName flags: $rlInc $rlLib"
+ # Check whether rl_completion_matches() has a signature we can use
+ # and disable that sub-feature if it doesn't.
+ if {![cctest \
+ -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 -source {
+ #include
+ #ifdef HAVE_EDITLINE
+ #include
+ #else
+ #include
+ #endif
+ static char * rcg(const char *z, int i){(void)z; (void)i; return 0;}
+ int main(void) {
+ char ** x = rl_completion_matches("one", rcg);
+ (void)x;
+ return 0;
+ }
+ }]} {
+ proj-warn "readline-style completion disabled due to rl_completion_matches() signature mismatch"
+ sqlite-add-shell-opt -DSQLITE_OMIT_READLINE_COMPLETION
+ }
+ return $editLibName
+ }
+
+ if {$failIfNotFound} {
+ proj-fatal "Explicit --$editLibName failed to find a matching library."
+ }
+ return "none"
+}; # sqlite-check-line-editing
+
+########################################################################
+# Runs sqlite-check-line-editing and adds a message around it In the
+# canonical build this must not be called before
+# sqlite-determine-codegen-tcl.
+proc sqlite-handle-line-editing {} {
+ msg-result "Line-editing support for the sqlite3 shell: [sqlite-check-line-editing]"
+}
+
+
+########################################################################
+# ICU - International Components for Unicode
+#
+# Handles these flags:
+#
+# --with-icu-ldflags=LDFLAGS
+# --with-icu-cflags=CFLAGS
+# --with-icu-config[=auto | pkg-config | /path/to/icu-config]
+# --enable-icu-collations
+#
+# --with-icu-config values:
+#
+# - auto: use the first one of (pkg-config, icu-config) found on the
+# system.
+# - pkg-config: use only pkg-config to determine flags
+# - /path/to/icu-config: use that to determine flags
+#
+# If --with-icu-config is used as neither pkg-config nor icu-config
+# are found, fail fatally.
+#
+# If both --with-icu-ldflags and --with-icu-config are provided, they
+# are cumulative. If neither are provided, icu-collations is not
+# honored and a warning is emitted if it is provided.
+#
+# Design note: though we could automatically enable ICU if the
+# icu-config binary or (pkg-config icu-io) are found, we specifically
+# do not. ICU is always an opt-in feature.
+proc sqlite-handle-icu {} {
+ define LDFLAGS_ICU [join [opt-val with-icu-ldflags ""]]
+ define CFLAGS_ICU [join [opt-val with-icu-cflags ""]]
+ if {[proj-opt-was-provided with-icu-config]} {
+ msg-result "Checking for ICU support..."
+ set icuConfigBin [opt-val with-icu-config]
+ set tryIcuConfigBin 1; # set to 0 if we end up using pkg-config
+ if {"auto" eq $icuConfigBin || "pkg-config" eq $icuConfigBin} {
+ if {[pkg-config-init 0] && [pkg-config icu-io]} {
+ # Maintenance reminder: historical docs say to use both of
+ # (icu-io, icu-uc). icu-uc lacks a required lib and icu-io has
+ # all of them on tested OSes.
+ set tryIcuConfigBin 0
+ define LDFLAGS_ICU [get-define PKG_ICU_IO_LDFLAGS]
+ define-append LDFLAGS_ICU [get-define PKG_ICU_IO_LIBS]
+ define CFLAGS_ICU [get-define PKG_ICU_IO_CFLAGS]
+ } elseif {"pkg-config" eq $icuConfigBin} {
+ proj-fatal "pkg-config cannot find package icu-io"
+ } else {
+ proj-assert {"auto" eq $icuConfigBin}
+ }
+ }
+ if {$tryIcuConfigBin} {
+ if {"auto" eq $icuConfigBin} {
+ set icuConfigBin [proj-first-bin-of \
+ /usr/local/bin/icu-config \
+ /usr/bin/icu-config]
+ if {"" eq $icuConfigBin} {
+ proj-indented-notice -error {
+ --with-icu-config=auto cannot find (pkg-config icu-io) or icu-config binary.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }
+ }
+ }
+ if {[file-isexec $icuConfigBin]} {
+ set x [exec $icuConfigBin --ldflags]
+ if {"" eq $x} {
+ proj-indented-notice -error \
+ [subst {
+ $icuConfigBin --ldflags returned no data.
+ On Ubuntu-like systems try:
+ --with-icu-ldflags='-licui18n -licuuc -licudata'
+ }]
+ }
+ define-append LDFLAGS_ICU $x
+ set x [exec $icuConfigBin --cppflags]
+ define-append CFLAGS_ICU $x
+ } else {
+ proj-fatal "--with-icu-config=$icuConfigBin does not refer to an executable"
+ }
+ }
+ }
+ set ldflags [define LDFLAGS_ICU [string trim [get-define LDFLAGS_ICU]]]
+ set cflags [define CFLAGS_ICU [string trim [get-define CFLAGS_ICU]]]
+ if {"" ne $ldflags} {
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU
+ msg-result "Enabling ICU support with flags: $ldflags $cflags"
+ if {[opt-bool icu-collations]} {
+ msg-result "Enabling ICU collations."
+ sqlite-add-feature-flag -shell -DSQLITE_ENABLE_ICU_COLLATIONS
+ # Recall that shell.c builds with sqlite3.c
+ }
+ } elseif {[opt-bool icu-collations]} {
+ proj-warn "ignoring --enable-icu-collations because neither --with-icu-ldflags nor --with-icu-config provided any linker flags"
+ } else {
+ msg-result "ICU support is disabled."
+ }
+}; # sqlite-handle-icu
+
+
+########################################################################
+# Handles the --enable-load-extension flag. Returns 1 if the support
+# is enabled, else 0. If support for that feature is not found, a
+# fatal error is triggered if --enable-load-extension is explicitly
+# provided, else a loud warning is instead emited. If
+# --disable-load-extension is used, no check is performed.
+#
+# Makes the following environment changes:
+#
+# - defines LDFLAGS_DLOPEN to any linker flags needed for this
+# feature. It may legally be empty on some systems where dlopen()
+# is in libc.
+#
+# - If the feature is not available, adds
+# -DSQLITE_OMIT_LOAD_EXTENSION=1 to the feature flags list.
+proc sqlite-handle-load-extension {} {
+ define LDFLAGS_DLOPEN ""
+ set found 0
+ proj-if-opt-truthy load-extension {
+ set found [proj-check-function-in-lib dlopen dl]
+ if {$found} {
+ define LDFLAGS_DLOPEN [get-define lib_dlopen]
+ undefine lib_dlopen
+ } else {
+ if {[proj-opt-was-provided load-extension]} {
+ # Explicit --enable-load-extension: fail if not found
+ proj-indented-notice -error {
+ --enable-load-extension was provided but dlopen()
+ not found. Use --disable-load-extension to bypass this
+ check.
+ }
+ } else {
+ # It was implicitly enabled: warn if not found
+ proj-indented-notice {
+ WARNING: dlopen() not found, so loadable module support will
+ be disabled. Use --disable-load-extension to bypass this
+ check.
+ }
+ }
+ }
+ }
+ if {$found} {
+ msg-result "Loadable extension support enabled."
+ } else {
+ msg-result "Disabling loadable extension support. Use --enable-load-extensions to enable them."
+ sqlite-add-feature-flag {-DSQLITE_OMIT_LOAD_EXTENSION=1}
+ }
+ return $found
+}
+
+########################################################################
+# Handles the --enable-math flag.
+proc sqlite-handle-math {} {
+ proj-if-opt-truthy math {
+ if {![proj-check-function-in-lib ceil m]} {
+ user-error "Cannot find libm functions. Use --disable-math to bypass this."
+ }
+ define LDFLAGS_MATH [get-define lib_ceil]
+ undefine lib_ceil
+ sqlite-add-feature-flag {-DSQLITE_ENABLE_MATH_FUNCTIONS}
+ msg-result "Enabling math SQL functions [get-define LDFLAGS_MATH]"
+ } {
+ define LDFLAGS_MATH ""
+ msg-result "Disabling math SQL functions"
+ }
+}
+
+########################################################################
+# If this OS looks like a Mac, checks for the Mac-specific
+# -current_version and -compatibility_version linker flags. Defines
+# LDFLAGS_MAC_CVERSION to an empty string and returns 0 if they're not
+# supported, else defines that to the linker flags and returns 1.
+#
+# We don't check this on non-Macs because this whole thing is a
+# libtool compatibility kludge to account for a version stamp which
+# libtool applied only on Mac platforms.
+#
+# Based on https://sqlite.org/forum/forumpost/9dfd5b8fd525a5d7.
+proc sqlite-handle-mac-cversion {} {
+ define LDFLAGS_MAC_CVERSION ""
+ set rc 0
+ if {[proj-looks-like-mac]} {
+ cc-with {-link 1} {
+ # These version numbers are historical libtool-defined values, not
+ # library-defined ones
+ if {[cc-check-flags "-Wl,-current_version,9.6.0"]
+ && [cc-check-flags "-Wl,-compatibility_version,9.0.0"]} {
+ define LDFLAGS_MAC_CVERSION "-Wl,-compatibility_version,9.0.0 -Wl,-current_version,9.6.0"
+ set rc 1
+ } elseif {[cc-check-flags "-compatibility_version 9.0.0"]
+ && [cc-check-flags "-current_version 9.6.0"]} {
+ define LDFLAGS_MAC_CVERSION "-compatibility_version 9.0.0 -current_version 9.6.0"
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# If this is a Mac platform, check for support for
+# -Wl,-install_name,... and, if it's set, define
+# LDFLAGS_MAC_INSTALL_NAME to a variant of that string which is
+# intended to expand at make-time, else set LDFLAGS_MAC_INSTALL_NAME
+# to an empty string.
+#
+# https://sqlite.org/forum/forumpost/5651662b8875ec0a
+proc sqlite-handle-mac-install-name {} {
+ define LDFLAGS_MAC_INSTALL_NAME ""; # {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
+ set rc 0
+ if {[proj-looks-like-mac]} {
+ cc-with {-link 1} {
+ if {[cc-check-flags "-Wl,-install_name,/usr/local/lib/libsqlite3.dylib"]} {
+ define LDFLAGS_MAC_INSTALL_NAME {-Wl,-install_name,"$(install-dir.lib)/$(libsqlite3.DLL)"}
+ set rc 1
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# Handles the --dll-basename configure flag. [define]'s
+# SQLITE_DLL_BASENAME to the DLL's preferred base name (minus
+# extension). If --dll-basename is not provided then this is always
+# "libsqlite3", otherwise it may use a different value based on the
+# value of [get-define host].
+proc sqlite-handle-dll-basename {} {
+ if {[proj-opt-was-provided dll-basename]} {
+ set dn [join [opt-val dll-basename] ""]
+ if {$dn in {none default}} { set dn libsqlite3 }
+ } else {
+ set dn libsqlite3
+ }
+ if {$dn in {auto ""}} {
+ switch -glob -- [get-define host] {
+ *-*-cygwin { set dn cygsqlite3-0 }
+ *-*-ming* { set dn libsqlite3-0 }
+ *-*-msys { set dn msys-sqlite3-0 }
+ default { set dn libsqlite3 }
+ }
+ }
+ define SQLITE_DLL_BASENAME $dn
+}
+
+########################################################################
+# [define]s LDFLAGS_OUT_IMPLIB to either an empty string or to a
+# -Wl,... flag for the platform-specific --out-implib flag, which is
+# used for building an "import library .dll.a" file on some platforms
+# (e.g. msys2, mingw). Returns 1 if supported, else 0.
+#
+# The name of the import library is [define]d in SQLITE_OUT_IMPLIB.
+#
+# If the configure flag --out-implib is not used then this is a no-op.
+# If that flag is used but the capability is not available, a fatal
+# error is triggered.
+#
+# This feature is specifically opt-in because it's supported on far
+# more platforms than actually need it and enabling it causes creation
+# of libsqlite3.so.a files which are unnecessary in most environments.
+#
+# Added in response to: https://sqlite.org/forum/forumpost/0c7fc097b2
+#
+# Platform notes:
+#
+# - cygwin sqlite packages historically install no .dll.a file.
+#
+# - msys2 and mingw sqlite packages historically install
+# /usr/lib/libsqlite3.dll.a despite the DLL being in
+# /usr/bin/msys-sqlite3-0.dll.
+proc sqlite-handle-out-implib {} {
+ define LDFLAGS_OUT_IMPLIB ""
+ define SQLITE_OUT_IMPLIB ""
+ set rc 0
+ if {[proj-opt-was-provided out-implib]} {
+ set olBaseName [join [opt-val out-implib] ""]
+ if {$olBaseName in {auto ""}} {
+ set olBaseName "libsqlite3" ;# [get-define SQLITE_DLL_BASENAME]
+ # Based on discussions with mingw/msys users, the import lib
+ # should always be called libsqlite3.dll.a even on platforms
+ # which rename libsqlite3.dll to something else.
+ }
+ if {$olBaseName ne "none"} {
+ cc-with {-link 1} {
+ set dll "${olBaseName}[get-define TARGET_DLLEXT]"
+ set flags [proj-cc-check-Wl-flag --out-implib ${dll}.a]
+ if {"" ne $flags} {
+ define LDFLAGS_OUT_IMPLIB $flags
+ define SQLITE_OUT_IMPLIB ${dll}.a
+ set rc 1
+ }
+ }
+ if {!$rc} {
+ user-error "--out-implib is not supported on this platform"
+ }
+ }
+ }
+ return $rc
+}
+
+########################################################################
+# If the given platform identifier (defaulting to [get-define host])
+# appears to be one of the Unix-on-Windows environments, returns a
+# brief symbolic name for that environment, else returns an empty
+# string.
+#
+# It does not distinguish between msys and msys2, returning msys for
+# both. The build does not, as of this writing, specifically support
+# msys v1.
+proc sqlite-env-is-unix-on-windows {{envTuple ""}} {
+ if {"" eq $envTuple} {
+ set envTuple [get-define host]
+ }
+ set name ""
+ switch -glob -- $envTuple {
+ *-*-cygwin { set name cygwin }
+ *-*-ming* { set name mingw }
+ *-*-msys { set name msys }
+ }
+ return $name;
+}
+
+########################################################################
+# Performs various tweaks to the build which are only relevant on
+# certain platforms, e.g. Mac and "Unix on Windows" platforms (msys2,
+# cygwin, ...).
+#
+# 1) DLL installation:
+#
+# [define]s SQLITE_DLL_INSTALL_RULES to a symbolic name suffix for a
+# set of "make install" rules to use for installation of the DLL
+# deliverable. The makefile is tasked with with providing rules named
+# install-dll-NAME which runs the installation for that set, as well
+# as providing a rule named install-dll which resolves to
+# install-dll-NAME (perhaps indirectly, depending on whether the DLL
+# is (de)activated).
+#
+# The default value is "unix-generic".
+#
+# 2) --out-implib:
+#
+# On platforms where an "import library" is conventionally used but
+# --out-implib was not explicitly used, automatically add that flag.
+# This conventionally applies to the "Unix on Windows" environments
+# like msys and cygwin.
+#
+# 3) --dll-basename:
+#
+# On the same platforms addressed by --out-implib, if --dll-basename
+# is not specified, --dll-basename=auto is implied.
+proc sqlite-handle-env-quirks {} {
+ set instName unix-generic; # name of installation rules set
+ set autoDll 0; # true if --out-implib/--dll-basename should be implied
+ set host [get-define host]
+ switch -glob -- $host {
+ *apple* -
+ *darwin* { set instName darwin }
+ default {
+ set x [sqlite-env-is-unix-on-windows $host]
+ if {"" ne $x} {
+ set instName $x
+ set autoDll 1
+ }
+ }
+ }
+ define SQLITE_DLL_INSTALL_RULES $instName
+ if {$autoDll} {
+ if {![proj-opt-was-provided out-implib]} {
+ # Imply --out-implib=auto
+ proj-indented-notice [subst -nocommands -nobackslashes {
+ NOTICE: auto-enabling --out-implib for environment [$host].
+ Use --out-implib=none to disable this special case
+ or --out-implib=auto to squelch this notice.
+ }]
+ proj-opt-set out-implib auto
+ }
+ if {![proj-opt-was-provided dll-basename]} {
+ # Imply --dll-basename=auto
+ proj-indented-notice [subst -nocommands -nobackslashes {
+ NOTICE: auto-enabling --dll-basename for environment [$host].
+ Use --dll-basename=default to disable this special case
+ or --dll-basename=auto to squelch this notice.
+ }]
+ proj-opt-set dll-basename auto
+ }
+ }
+ sqlite-handle-dll-basename
+ sqlite-handle-out-implib
+ sqlite-handle-mac-cversion
+ sqlite-handle-mac-install-name
+}
+
+########################################################################
+# Perform some late-stage work and generate the configure-process
+# output file(s).
+proc sqlite-process-dot-in-files {} {
+ ########################################################################
+ # When cross-compiling, we have to avoid using the -s flag to
+ # /usr/bin/install:
+ # https://sqlite.org/forum/forumpost/9a67df63eda9925c
+ define IS_CROSS_COMPILING $::sqliteConfig(is-cross-compiling)
+
+ # Finish up handling of the various feature flags here because it's
+ # convenient for both the canonical build and autoconf bundles that
+ # it be done here.
+ sqlite-handle-common-feature-flags
+ sqlite-finalize-feature-flags
+
+ ########################################################################
+ # "Re-export" the autoconf-conventional --XYZdir flags into something
+ # which is more easily overridable from a make invocation. See the docs
+ # for [proj-remap-autoconf-dir-vars] for the explanation of why.
+ #
+ # We do this late in the config process, immediately before we export
+ # the Makefile and other generated files, so that configure tests
+ # which make make use of the autotools-conventional flags
+ # (e.g. [proj-check-rpath]) may do so before we "mangle" them here.
+ proj-remap-autoconf-dir-vars
+
+ proj-make-from-dot-in -touch Makefile sqlite3.pc
+ make-config-header sqlite_cfg.h \
+ -bare {SIZEOF_* HAVE_DECL_*} \
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG
+ TARGET_* USE_GCOV TCL_*} \
+ -auto {HAVE_* PACKAGE_*} \
+ -none *
+ proj-touch sqlite_cfg.h ; # help avoid frequent unnecessary @SQLITE_AUTORECONFIG@
+}
+
+########################################################################
+# Perform some high-level validation on the generated files...
+#
+# 1) Ensure that no unresolved @VAR@ placeholders are in files which
+# use those.
+#
+# 2) TBD
+proc sqlite-post-config-validation {} {
+ # Check #1: ensure that files which get filtered for @VAR@ do not
+ # contain any unresolved @VAR@ refs. That may indicate an
+ # unexported/unused var or a typo.
+ set srcdir $::autosetup(srcdir)
+ foreach f [list Makefile sqlite3.pc \
+ $srcdir/tool/emcc.sh \
+ $srcdir/ext/wasm/config.make] {
+ if {![file exists $f]} continue
+ set lnno 1
+ foreach line [proj-file-content-list $f] {
+ if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} {
+ error "Unresolved reference to $match at line $lnno of $f"
+ }
+ incr lnno
+ }
+ }
+}
+
+########################################################################
+# Handle --with-wasi-sdk[=DIR]
+#
+# This must be run relatively early on because it may change the
+# toolchain and disable a number of config options. However, in the
+# canonical build this must come after [sqlite-check-common-bins].
+proc sqlite-handle-wasi-sdk {} {
+ set wasiSdkDir [opt-val with-wasi-sdk] ; # ??? [lindex [opt-val with-wasi-sdk] end]
+ define HAVE_WASI_SDK 0
+ if {$wasiSdkDir eq ""} {
+ return 0
+ } elseif {$::sqliteConfig(is-cross-compiling)} {
+ proj-fatal "Cannot combine --with-wasi-sdk with cross-compilation"
+ }
+ msg-result "Checking WASI SDK directory \[$wasiSdkDir]... "
+ proj-affirm-files-exist -v {*}[prefix "$wasiSdkDir/bin/" {clang wasm-ld ar}]
+ define HAVE_WASI_SDK 1
+ define WASI_SDK_DIR $wasiSdkDir
+ # Disable numerous options which we know either can't work or are
+ # not useful in this build...
+ msg-result "Using wasi-sdk clang. Disabling CLI shell and modifying config flags:"
+ # Boolean (--enable-/--disable-) flags which must be switched off:
+ foreach opt {
+ dynlink-tools
+ editline
+ gcov
+ icu-collations
+ load-extension
+ readline
+ shared
+ tcl
+ threadsafe
+ } {
+ if {[opt-bool $opt]} {
+ msg-result " --disable-$opt"
+ proj-opt-set $opt 0
+ }
+ }
+ # Non-boolean flags which need to be cleared:
+ foreach opt {
+ with-emsdk
+ with-icu-config
+ with-icu-ldflags
+ with-icu-cflags
+ with-linenoise
+ with-tcl
+ } {
+ if {[proj-opt-was-provided $opt]} {
+ msg-result " removing --$opt"
+ proj-opt-set $opt ""
+ }
+ }
+ # Remember that we now have a discrepancy beteween
+ # $::sqliteConfig(is-cross-compiling) and [proj-is-cross-compiling].
+ set ::sqliteConfig(is-cross-compiling) 1
+
+ #
+ # Changing --host and --target have no effect here except to
+ # possibly cause confusion. Autosetup has finished processing them
+ # by this point.
+ #
+ # host_alias=wasm32-wasi
+ # target=wasm32-wasi
+ #
+ # Merely changing CC, LD, and AR to the wasi-sdk's is enough to get
+ # sqlite3.o building in WASM format.
+ #
+ define CC "${wasiSdkDir}/bin/clang"
+ define LD "${wasiSdkDir}/bin/wasm-ld"
+ define AR "${wasiSdkDir}/bin/ar"
+ #define STRIP "${wasiSdkDir}/bin/strip"
+ return 1
+}; # sqlite-handle-wasi-sdk
+
+########################################################################
+# TCL...
+#
+# sqlite-check-tcl performs most of the --with-tcl and --with-tclsh
+# handling. Some related bits and pieces are performed before and
+# after that function is called.
+#
+# Important [define]'d vars:
+#
+# - HAVE_TCL indicates whether we have a tclsh suitable for building
+# the TCL SQLite extension and, by extension, the testing
+# infrastructure. This must only be 1 for environments where
+# tclConfig.sh can be found.
+#
+# - TCLSH_CMD is the path to the canonical tclsh or "". It never
+# refers to jimtcl.
+#
+# - TCL_CONFIG_SH is the path to tclConfig.sh or "".
+#
+# - TCLLIBDIR is the dir to which libtclsqlite3 gets installed.
+#
+# - BTCLSH = the path to the tcl interpreter used for in-tree code
+# generation. It may be jimtcl or the canonical tclsh but may not
+# be empty - this tree requires TCL to generated numerous
+# components.
+#
+# If --tcl or --with-tcl are provided but no TCL is found, this
+# function fails fatally. If they are not explicitly provided then
+# failure to find TCL is not fatal but a loud warning will be emitted.
+#
+proc sqlite-check-tcl {} {
+ define TCLSH_CMD false ; # Significant is that it exits with non-0
+ define HAVE_TCL 0 ; # Will be enabled via --tcl or a successful search
+ define TCLLIBDIR "" ; # Installation dir for TCL extension lib
+ define TCL_CONFIG_SH ""; # full path to tclConfig.sh
+
+ # Clear out all vars which would be set by tclConfigToAutoDef.sh, so
+ # that the late-config validation of @VARS@ works even if
+ # --disable-tcl is used.
+ foreach k {TCL_INCLUDE_SPEC TCL_LIB_SPEC TCL_STUB_LIB_SPEC TCL_EXEC_PREFIX TCL_VERSION} {
+ define $k ""
+ }
+
+ file delete -force ".tclenv.sh"; # ensure no stale state from previous configures.
+ if {![opt-bool tcl]} {
+ proj-indented-notice {
+ NOTE: TCL is disabled via --disable-tcl. This means that none
+ of the TCL-based components will be built, including tests
+ and sqlite3_analyzer.
+ }
+ return
+ }
+ # TODO: document the steps this is taking.
+ set srcdir $::autosetup(srcdir)
+ msg-result "Checking for a suitable tcl... "
+ proj-assert [proj-opt-truthy tcl]
+ set use_tcl 1
+ set with_tclsh [opt-val with-tclsh]
+ set with_tcl [opt-val with-tcl]
+ if {"prefix" eq $with_tcl} {
+ set with_tcl [get-define prefix]
+ }
+ msg-debug "sqlite-check-tcl: use_tcl ${use_tcl}"
+ msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
+ msg-debug "sqlite-check-tcl: with_tcl=$with_tcl"
+ if {"" eq $with_tclsh && "" eq $with_tcl} {
+ # If neither --with-tclsh nor --with-tcl are provided, try to find
+ # a workable tclsh.
+ set with_tclsh [proj-first-bin-of tclsh9.0 tclsh8.6 tclsh]
+ msg-debug "sqlite-check-tcl: with_tclsh=${with_tclsh}"
+ }
+
+ set doConfigLookup 1 ; # set to 0 to test the tclConfig.sh-not-found cases
+ if {"" ne $with_tclsh} {
+ # --with-tclsh was provided or found above. Validate it and use it
+ # to trump any value passed via --with-tcl=DIR.
+ if {![file-isexec $with_tclsh]} {
+ proj-fatal "TCL shell $with_tclsh is not executable"
+ } else {
+ define TCLSH_CMD $with_tclsh
+ #msg-result "Using tclsh: $with_tclsh"
+ }
+ if {$doConfigLookup &&
+ [catch {exec $with_tclsh $srcdir/tool/find_tclconfig.tcl} result] == 0} {
+ set with_tcl $result
+ }
+ if {"" ne $with_tcl && [file isdir $with_tcl]} {
+ msg-result "$with_tclsh recommends the tclConfig.sh from $with_tcl"
+ } else {
+ proj-warn "$with_tclsh is unable to recommend a tclConfig.sh"
+ set use_tcl 0
+ }
+ }
+ set cfg ""
+ set tclSubdirs {tcl9.0 tcl8.6 lib}
+ while {$use_tcl} {
+ if {"" ne $with_tcl} {
+ # Ensure that we can find tclConfig.sh under ${with_tcl}/...
+ if {$doConfigLookup} {
+ if {[file readable "${with_tcl}/tclConfig.sh"]} {
+ set cfg "${with_tcl}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${with_tcl}/$i/tclConfig.sh"]} {
+ set cfg "${with_tcl}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ }
+ if {"" eq $cfg} {
+ proj-fatal "No tclConfig.sh found under ${with_tcl}"
+ }
+ } else {
+ # If we have not yet found a tclConfig.sh file, look in $libdir
+ # which is set automatically by autosetup or via the --prefix
+ # command-line option. See
+ # https://sqlite.org/forum/forumpost/e04e693439a22457
+ set libdir [get-define libdir]
+ if {[file readable "${libdir}/tclConfig.sh"]} {
+ set cfg "${libdir}/tclConfig.sh"
+ } else {
+ foreach i $tclSubdirs {
+ if {[file readable "${libdir}/$i/tclConfig.sh"]} {
+ set cfg "${libdir}/$i/tclConfig.sh"
+ break
+ }
+ }
+ }
+ if {![file readable $cfg]} {
+ break
+ }
+ }
+ msg-result "Using tclConfig.sh: $cfg"
+ break
+ }
+ define TCL_CONFIG_SH $cfg
+ # Export a subset of tclConfig.sh to the current TCL-space. If $cfg
+ # is an empty string, this emits empty-string entries for the
+ # various options we're interested in.
+ eval [exec sh "$srcdir/tool/tclConfigShToAutoDef.sh" "$cfg"]
+ # ---------^^ a Windows/msys workaround, without which it cannot
+ # exec a .sh file: https://sqlite.org/forum/forumpost/befb352a42a7cd6d
+
+ if {"" eq $with_tclsh && $cfg ne ""} {
+ # We have tclConfig.sh but no tclsh. Attempt to locate a tclsh
+ # based on info from tclConfig.sh.
+ proj-assert {"" ne [get-define TCL_EXEC_PREFIX]}
+ set with_tclsh [get-define TCL_EXEC_PREFIX]/bin/tclsh[get-define TCL_VERSION]
+ if {![file-isexec $with_tclsh]} {
+ set with_tclsh2 [get-define TCL_EXEC_PREFIX]/bin/tclsh
+ if {![file-isexec $with_tclsh2]} {
+ proj-warn "Cannot find a usable tclsh (tried: $with_tclsh $with_tclsh2)"
+ } else {
+ set with_tclsh $with_tclsh2
+ }
+ }
+ }
+ define TCLSH_CMD $with_tclsh
+ if {$use_tcl} {
+ # Set up the TCLLIBDIR
+ #
+ # 2024-10-28: calculation of TCLLIBDIR is now done via the shell
+ # in main.mk (search it for T.tcl.env.sh) so that
+ # static/hand-written makefiles which import main.mk do not have
+ # to define that before importing main.mk. Even so, we export
+ # TCLLIBDIR from here, which will cause the canonical makefile to
+ # use this one rather than to re-calculate it at make-time.
+ set tcllibdir [get-env TCLLIBDIR ""]
+ if {"" eq $tcllibdir} {
+ # Attempt to extract TCLLIBDIR from TCL's $auto_path
+ if {"" ne $with_tclsh &&
+ [catch {exec echo "puts stdout \$auto_path" | "$with_tclsh"} result] == 0} {
+ foreach i $result {
+ if {[file isdir $i]} {
+ set tcllibdir $i/sqlite3
+ break
+ }
+ }
+ } else {
+ proj-warn "Cannot determine TCLLIBDIR."
+ # The makefile will fail fatally in this case if a target is
+ # invoked which requires TCLLIBDIR.
+ }
+ }
+ #if {"" ne $tcllibdir} { msg-result "TCLLIBDIR = ${tcllibdir}"; }
+ define TCLLIBDIR $tcllibdir
+ }; # find TCLLIBDIR
+
+ if {[file-isexec $with_tclsh]} {
+ msg-result "Using tclsh: $with_tclsh"
+ if {$cfg ne ""} {
+ define HAVE_TCL 1
+ } else {
+ proj-warn "Found tclsh but no tclConfig.sh."
+ }
+ }
+ show-notices
+ # If TCL is not found: if it was explicitly requested then fail
+ # fatally, else just emit a warning. If we can find the APIs needed
+ # to generate a working JimTCL then that will suffice for build-time
+ # TCL purposes (see: proc sqlite-determine-codegen-tcl).
+ if {![get-define HAVE_TCL] &&
+ ([proj-opt-was-provided tcl] || [proj-opt-was-provided with-tcl])} {
+ proj-fatal "TCL support was requested but no tclConfig.sh could be found."
+ }
+ if {"" eq $cfg} {
+ proj-assert {0 == [get-define HAVE_TCL]}
+ proj-indented-notice {
+ WARNING: Cannot find a usable tclConfig.sh file. Use
+ --with-tcl=DIR to specify a directory where tclConfig.sh can be
+ found. SQLite does not use TCL internally, but some optional
+ components require TCL, including tests and sqlite3_analyzer.
+ }
+ }
+}; # sqlite-check-tcl
+
+########################################################################
+# sqlite-determine-codegen-tcl checks which TCL to use as a code
+# generator. By default, prefer jimsh simply because we have it
+# in-tree (it's part of autosetup) unless --with-tclsh=X is used, in
+# which case prefer X.
+#
+# Returns the human-readable name of the TCL it selects. Fails fatally
+# if it cannot detect a TCL appropriate for code generation.
+#
+# Defines:
+#
+# - BTCLSH = the TCL shell used for code generation. It may set this
+# to an unexpanded makefile var name.
+#
+# - CFLAGS_JIMSH = any flags needed for buildng a BTCLSH-compatible
+# jimsh. The defaults may be passed on to configure as
+# CFLAGS_JIMSH=...
+proc sqlite-determine-codegen-tcl {} {
+ msg-result "Checking for TCL to use for code generation... "
+ define CFLAGS_JIMSH [proj-get-env CFLAGS_JIMSH {-O1}]
+ set cgtcl [opt-val with-tclsh jimsh]
+ if {"jimsh" ne $cgtcl} {
+ # When --with-tclsh=X is used, use that for all TCL purposes,
+ # including in-tree code generation, per developer request.
+ define BTCLSH "\$(TCLSH_CMD)"
+ return $cgtcl
+ }
+ set flagsToRestore {CC CFLAGS AS_CFLAGS CPPFLAGS AS_CPPFLAGS LDFLAGS LINKFLAGS LIBS CROSS}
+ define-push $flagsToRestore {
+ # We have to swap CC to CC_FOR_BUILD for purposes of the various
+ # [cc-...] tests below. Recall that --with-wasi-sdk may have
+ # swapped out CC with one which is not appropriate for this block.
+ # Per consulation with autosetup's creator, doing this properly
+ # requires us to [define-push] the whole $flagsToRestore list
+ # (plus a few others which are not relevant in this tree).
+ #
+ # These will get set to their previous values at the end of this
+ # block.
+ foreach flag $flagsToRestore {define $flag ""}
+ define CC [get-define CC_FOR_BUILD]
+ # These headers are technically optional for JimTCL but necessary if
+ # we want to use it for code generation:
+ set sysh [cc-check-includes dirent.h sys/time.h]
+ # jimsh0.c hard-codes #define's for HAVE_DIRENT_H and
+ # HAVE_SYS_TIME_H on the platforms it supports, so we do not
+ # need to add -D... flags for those. We check for them here only
+ # so that we can avoid the situation that we later, at
+ # make-time, try to compile jimsh but it then fails due to
+ # missing headers (i.e. fail earlier rather than later).
+ if {$sysh && [cc-check-functions realpath]} {
+ define-append CFLAGS_JIMSH -DHAVE_REALPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {$sysh && [cc-check-functions _fullpath]} {
+ # _fullpath() is a Windows API. It's not entirely clear
+ # whether we need to add {-DHAVE_SYS_TIME_H -DHAVE_DIRENT_H}
+ # to CFLAGS_JIMSH in this case. On MinGW32 we definitely do
+ # not want to because it already hard-codes them. On _MSC_VER
+ # builds it does not.
+ define-append CFLAGS_JIMSH -DHAVE__FULLPATH
+ define BTCLSH "\$(JIMSH)"
+ set ::sqliteConfig(use-jim-for-codegen) 1
+ } elseif {[file-isexec [get-define TCLSH_CMD]]} {
+ set cgtcl [get-define TCLSH_CMD]
+ define BTCLSH "\$(TCLSH_CMD)"
+ } else {
+ # One last-ditch effort to find TCLSH_CMD: use info from
+ # tclConfig.sh to try to find a tclsh
+ if {"" eq [get-define TCLSH_CMD]} {
+ set tpre [get-define TCL_EXEC_PREFIX]
+ if {"" ne $tpre} {
+ set tv [get-define TCL_VERSION]
+ if {[file-isexec "${tpre}/bin/tclsh${tv}"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh${tv}"
+ } elseif {[file-isexec "${tpre}/bin/tclsh"]} {
+ define TCLSH_CMD "${tpre}/bin/tclsh"
+ }
+ }
+ }
+ set cgtcl [get-define TCLSH_CMD]
+ if {![file-isexec $cgtcl]} {
+ proj-fatal "Cannot find a tclsh to use for code generation."
+ }
+ define BTCLSH "\$(TCLSH_CMD)"
+ }
+ }; # /define-push $flagsToRestore
+ return $cgtcl
+}; # sqlite-determine-codegen-tcl
+
+########################################################################
+# Runs sqlite-check-tcl and sqlite-determine-codegen-tcl.
+proc sqlite-handle-tcl {} {
+ sqlite-check-tcl
+ msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
+}
+
+########################################################################
+# Handle the --enable/disable-rpath flag.
+proc sqlite-handle-rpath {} {
+ proj-check-rpath
+ # autosetup/cc-shared.tcl sets the rpath flag definition in
+ # [get-define SH_LINKRPATH], but it does so on a per-platform basis
+ # rather than as a compiler check. Though we should do a proper
+ # compiler check (as proj-check-rpath does), we may want to consider
+ # adopting its approach of clearing the rpath flags for environments
+ # for which sqlite-env-is-unix-on-windows returns a non-empty
+ # string.
+
+# if {[proj-opt-truthy rpath]} {
+# proj-check-rpath
+# } else {
+# msg-result "Disabling use of rpath."
+# define LDFLAGS_RPATH ""
+# }
+}
+
+########################################################################
+# If the --dump-defines configure flag is provided then emit a list of
+# all [define] values to config.defines.txt, else do nothing.
+proc sqlite-dump-defines {} {
+ proj-if-opt-truthy dump-defines {
+ make-config-header $::sqliteConfig(dump-defines-txt) \
+ -bare {SQLITE_OS* SQLITE_DEBUG USE_*} \
+ -str {BIN_* CC LD AR LDFLAG* OPT_*} \
+ -auto {*}
+ # achtung: ^^^^ whichever SQLITE_OS_foo flag which is set to 0 will
+ # get _undefined_ here unless it's part of the -bare set.
+ if {"" ne $::sqliteConfig(dump-defines-json)} {
+ msg-result "--dump-defines is creating $::sqliteConfig(dump-defines-json)"
+ ########################################################################
+ # Dump config-defines.json...
+ # Demonstrate (mis?)handling of spaces in JSON-export array values:
+ # define-append OPT_FOO.list {"-DFOO=bar baz" -DBAR="baz barre"}
+ define OPT_FEATURE_FLAGS.list [get-define OPT_FEATURE_FLAGS]
+ define OPT_SHELL.list [get-define OPT_SHELL]
+ set dumpDefsOpt {
+ -bare {SIZEOF_* HAVE_DECL_*}
+ -none {HAVE_CFLAG_* LDFLAGS_* SH_* SQLITE_AUTORECONFIG TARGET_* USE_GCOV TCL_*}
+ -array {*.list}
+ -auto {OPT_* PACKAGE_* HAVE_*}
+ }
+# if {$::sqliteConfig(dump-defines-json-include-lowercase)} {
+# lappend dumpDefsOpt -none {lib_*} ; # remnants from proj-check-function-in-lib and friends
+# lappend dumpDefsOpt -auto {[a-z]*}
+# }
+ lappend dumpDefsOpt -none *
+ proj-dump-defs-json $::sqliteConfig(dump-defines-json) {*}$dumpDefsOpt
+ undefine OPT_FEATURE_FLAGS.list
+ undefine OPT_SHELL.list
+ }
+ }
+}
diff --git a/autosetup/system.tcl b/autosetup/system.tcl
new file mode 100644
index 0000000000..05d378afdd
--- /dev/null
+++ b/autosetup/system.tcl
@@ -0,0 +1,420 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# This module supports common system interrogation and options
+# such as '--host', '--build', '--prefix', and setting 'srcdir', 'builddir', and 'EXEEXT'.
+#
+# It also support the "feature" naming convention, where searching
+# for a feature such as 'sys/type.h' defines 'HAVE_SYS_TYPES_H'.
+#
+# It defines the following variables, based on '--prefix' unless overridden by the user:
+#
+## datadir
+## sysconfdir
+## sharedstatedir
+## localstatedir
+## infodir
+## mandir
+## includedir
+#
+# If '--prefix' is not supplied, it defaults to '/usr/local' unless 'options-defaults { prefix ... }' is used *before*
+# including the 'system' module.
+
+if {[is-defined defaultprefix]} {
+ user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options"
+ options-defaults [list prefix [get-define defaultprefix]]
+}
+
+options {
+ host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
+ the application will run (defaults to the same value as --build)}
+ build:build-alias => {a complete or partial cpu-vendor-opsys for the system
+ where the application will be built (defaults to the
+ result of running config.guess)}
+ prefix:dir=/usr/local => {the target directory for the build (default: '@default@')}
+
+ # These (hidden) options are supported for autoconf/automake compatibility
+ exec-prefix:
+ bindir:
+ sbindir:
+ includedir:
+ mandir:
+ infodir:
+ libexecdir:
+ datadir:
+ libdir:
+ sysconfdir:
+ sharedstatedir:
+ localstatedir:
+ runstatedir:
+ maintainer-mode=0
+ dependency-tracking=0
+ silent-rules=0
+ program-prefix:
+ program-suffix:
+ program-transform-name:
+ x-includes:
+ x-libraries:
+}
+
+# @check-feature name { script }
+#
+# defines feature '$name' to the return value of '$script',
+# which should be 1 if found or 0 if not found.
+#
+# e.g. the following will define 'HAVE_CONST' to 0 or 1.
+#
+## check-feature const {
+## cctest -code {const int _x = 0;}
+## }
+proc check-feature {name code} {
+ msg-checking "Checking for $name..."
+ set r [uplevel 1 $code]
+ define-feature $name $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ }
+ return $r
+}
+
+# @have-feature name ?default=0?
+#
+# Returns the value of feature '$name' if defined, or '$default' if not.
+#
+# See 'feature-define-name' for how the "feature" name
+# is translated into the "define" name.
+#
+proc have-feature {name {default 0}} {
+ get-define [feature-define-name $name] $default
+}
+
+# @define-feature name ?value=1?
+#
+# Sets the feature 'define' to '$value'.
+#
+# See 'feature-define-name' for how the "feature" name
+# is translated into the "define" name.
+#
+proc define-feature {name {value 1}} {
+ define [feature-define-name $name] $value
+}
+
+# @feature-checked name
+#
+# Returns 1 if feature '$name' has been checked, whether true or not.
+#
+proc feature-checked {name} {
+ is-defined [feature-define-name $name]
+}
+
+# @feature-define-name name ?prefix=HAVE_?
+#
+# Converts a "feature" name to the corresponding "define",
+# e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'.
+#
+# Converts '*' to 'P' and all non-alphanumeric to underscore.
+#
+proc feature-define-name {name {prefix HAVE_}} {
+ string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
+}
+
+# @write-if-changed filename contents ?script?
+#
+# If '$filename' doesn't exist, or it's contents are different to '$contents',
+# the file is written and '$script' is evaluated.
+#
+# Otherwise a "file is unchanged" message is displayed.
+proc write-if-changed {file buf {script {}}} {
+ set old [readfile $file ""]
+ if {$old eq $buf && [file exists $file]} {
+ msg-result "$file is unchanged"
+ } else {
+ writefile $file $buf\n
+ uplevel 1 $script
+ }
+}
+
+
+# @include-file infile mapping
+#
+# The core of make-template, called recursively for each @include
+# directive found within that template so that this proc's result
+# is the fully-expanded template.
+#
+# The mapping parameter is how we expand @varname@ within the template.
+# We do that inline within this step only for @include directives which
+# can have variables in the filename arg. A separate substitution pass
+# happens when this recursive function returns, expanding the rest of
+# the variables.
+#
+proc include-file {infile mapping} {
+ # A stack of true/false conditions, one for each nested conditional
+ # starting with "true"
+ set condstack {1}
+ set result {}
+ set linenum 0
+ foreach line [split [readfile $infile] \n] {
+ incr linenum
+ if {[regexp {^@(if|else|endif)(\s*)(.*)} $line -> condtype condspace condargs]} {
+ if {$condtype eq "if"} {
+ if {[string length $condspace] == 0} {
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
+ }
+ if {[llength $condargs] == 1} {
+ # ABC => [get-define ABC] ni {0 ""}
+ # !ABC => [get-define ABC] in {0 ""}
+ lassign $condargs condvar
+ if {[regexp {^!(.*)} $condvar -> condvar]} {
+ set op in
+ } else {
+ set op ni
+ }
+ set condexpr "\[[list get-define $condvar]\] $op {0 {}}"
+ } else {
+ # Translate alphanumeric ABC into [get-define ABC] and leave the
+ # rest of the expression untouched
+ regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr
+ }
+ if {[catch [list expr $condexpr] condval]} {
+ dputs $condval
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
+ }
+ dputs "@$condtype: $condexpr => $condval"
+ }
+ if {$condtype ne "if"} {
+ if {[llength $condstack] <= 1} {
+ autosetup-error "$infile:$linenum: Error: @$condtype missing @if"
+ } elseif {[string length $condargs] && [string index $condargs 0] ne "#"} {
+ autosetup-error "$infile:$linenum: Error: Extra arguments after @$condtype"
+ }
+ }
+ switch -exact $condtype {
+ if {
+ # push condval
+ lappend condstack $condval
+ }
+ else {
+ # Toggle the last entry
+ set condval [lpop condstack]
+ set condval [expr {!$condval}]
+ lappend condstack $condval
+ }
+ endif {
+ if {[llength $condstack] == 0} {
+ user-notice "$infile:$linenum: Error: @endif missing @if"
+ }
+ lpop condstack
+ }
+ }
+ continue
+ }
+ # Only continue if the stack contains all "true"
+ if {"0" in $condstack} {
+ continue
+ }
+ if {[regexp {^@include\s+(.*)} $line -> filearg]} {
+ set incfile [string map $mapping $filearg]
+ if {[file exists $incfile]} {
+ lappend ::autosetup(deps) [file-normalize $incfile]
+ lappend result {*}[include-file $incfile $mapping]
+ } else {
+ user-error "$infile:$linenum: Include file $incfile is missing"
+ }
+ continue
+ }
+ if {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
+ define $var $val
+ continue
+ }
+ lappend result $line
+ }
+ return $result
+}
+
+
+# @make-template template ?outfile?
+#
+# Reads the input file '/$template' and writes the output file '$outfile'
+# (unless unchanged).
+# If '$outfile' is blank/omitted, '$template' should end with '.in' which
+# is removed to create the output file name.
+#
+# Each pattern of the form '@define@' is replaced with the corresponding
+# "define", if it exists, or left unchanged if not.
+#
+# The special value '@srcdir@' is substituted with the relative
+# path to the source directory from the directory where the output
+# file is created, while the special value '@top_srcdir@' is substituted
+# with the relative path to the top level source directory.
+#
+# Conditional sections may be specified as follows:
+## @if NAME eq "value"
+## lines
+## @else
+## lines
+## @endif
+#
+# Where 'NAME' is a defined variable name and '@else' is optional.
+# Note that variables names *must* start with an uppercase letter.
+# If the expression does not match, all lines through '@endif' are ignored.
+#
+# The alternative forms may also be used:
+## @if NAME (true if the variable is defined, but not empty and not "0")
+## @if !NAME (opposite of the form above)
+## @if
+#
+# In the general Tcl expression, any words beginning with an uppercase letter
+# are translated into [get-define NAME]
+#
+# Expressions may be nested
+#
+proc make-template {template {out {}}} {
+ set infile [file join $::autosetup(srcdir) $template]
+
+ if {![file exists $infile]} {
+ user-error "Template $template is missing"
+ }
+
+ # Define this as late as possible
+ define AUTODEPS $::autosetup(deps)
+
+ if {$out eq ""} {
+ if {[file ext $template] ne ".in"} {
+ autosetup-error "make_template $template has no target file and can't guess"
+ }
+ set out [file rootname $template]
+ }
+
+ set outdir [file dirname $out]
+
+ # Make sure the directory exists
+ file mkdir $outdir
+
+ # Set up srcdir and top_srcdir to be relative to the target dir
+ define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
+ define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
+
+ # Build map from global defines to their values so they can be
+ # substituted into @include file names.
+ proc build-define-mapping {} {
+ set mapping {}
+ foreach {n v} [array get ::define] {
+ lappend mapping @$n@ $v
+ }
+ return $mapping
+ }
+ set mapping [build-define-mapping]
+
+ set result [include-file $infile $mapping]
+
+ # Rebuild the define mapping in case we ran across @define
+ # directives in the template or a file it @included, then
+ # apply that mapping to the expanded template.
+ set mapping [build-define-mapping]
+ write-if-changed $out [string map $mapping [join $result \n]] {
+ msg-result "Created [relative-path $out] from [relative-path $template]"
+ }
+}
+
+proc system-init {} {
+ global autosetup
+
+ # build/host tuples and cross-compilation prefix
+ opt-str build build ""
+ define build_alias $build
+ if {$build eq ""} {
+ define build [config_guess]
+ } else {
+ define build [config_sub $build]
+ }
+
+ opt-str host host ""
+ define host_alias $host
+ if {$host eq ""} {
+ define host [get-define build]
+ set cross ""
+ } else {
+ define host [config_sub $host]
+ set cross $host-
+ }
+ define cross [get-env CROSS $cross]
+
+ # build/host _cpu, _vendor and _os
+ foreach type {build host} {
+ set v [get-define $type]
+ if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
+ user-error "Invalid canonical $type: $v"
+ }
+ define ${type}_cpu $cpu
+ define ${type}_vendor $vendor
+ define ${type}_os $os
+ }
+
+ opt-str prefix prefix /usr/local
+
+ # These are for compatibility with autoconf
+ define target [get-define host]
+ define prefix $prefix
+ define builddir $autosetup(builddir)
+ define srcdir $autosetup(srcdir)
+ define top_srcdir $autosetup(srcdir)
+ define abs_top_srcdir [file-normalize $autosetup(srcdir)]
+ define abs_top_builddir [file-normalize $autosetup(builddir)]
+
+ # autoconf supports all of these
+ define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
+ foreach {name defpath} {
+ bindir /bin
+ sbindir /sbin
+ libexecdir /libexec
+ libdir /lib
+ } {
+ define $name [opt-str $name o $exec_prefix$defpath]
+ }
+ foreach {name defpath} {
+ datadir /share
+ sharedstatedir /com
+ infodir /share/info
+ mandir /share/man
+ includedir /include
+ } {
+ define $name [opt-str $name o $prefix$defpath]
+ }
+ if {$prefix ne {/usr}} {
+ opt-str sysconfdir sysconfdir $prefix/etc
+ } else {
+ opt-str sysconfdir sysconfdir /etc
+ }
+ define sysconfdir $sysconfdir
+
+ define localstatedir [opt-str localstatedir o /var]
+ define runstatedir [opt-str runstatedir o /run]
+
+ define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+
+ # These could be used to generate Makefiles following some automake conventions
+ define AM_SILENT_RULES [opt-bool silent-rules]
+ define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
+ define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
+
+ # Windows vs. non-Windows
+ switch -glob -- [get-define host] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define-feature windows
+ define EXEEXT .exe
+ }
+ default {
+ define EXEEXT ""
+ }
+ }
+
+ # Display
+ msg-result "Host System...[get-define host]"
+ msg-result "Build System...[get-define build]"
+}
+
+system-init
diff --git a/configure b/configure
index 208909c9b7..64b60f8b35 100755
--- a/configure
+++ b/configure
@@ -1,16305 +1,4 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for sqlcipher 3.44.2.
-#
-#
-# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
-# Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; then
- PATH_SEPARATOR=:
- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
- PATH_SEPARATOR=';'
- }
-fi
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-# Use a proper internal environment variable to ensure we don't fall
- # into an infinite loop, continuously re-executing ourselves.
- if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
- _as_can_reexec=no; export _as_can_reexec;
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
- fi
- # We don't want this to propagate to other subprocesses.
- { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="as_nop=:
-if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '\${1+\"\$@\"}'='\"\$@\"'
- setopt NO_GLOB_SUBST
-else \$as_nop
- case \`(set -o) 2>/dev/null\` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-"
- as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" )
-then :
-
-else \$as_nop
- exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-blah=\$(echo \$(echo blah))
-test x\"\$blah\" = xblah || exit 1
-test -x / || exit 1"
- as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
- as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
- eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
- test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-
- test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
- ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
- ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
- ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
- PATH=/empty FPATH=/empty; export PATH FPATH
- test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
- || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null
-then :
- as_have_required=yes
-else $as_nop
- as_have_required=no
-fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
-then :
-
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
- case $as_dir in #(
- /*)
- for as_base in sh bash ksh sh5; do
- # Try only shells that exist, to save several forks.
- as_shell=$as_dir$as_base
- if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$as_shell as_have_required=yes
- if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
-then :
- break 2
-fi
-fi
- done;;
- esac
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
-then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi
-fi
-
-
- if test "x$CONFIG_SHELL" != x
-then :
- export CONFIG_SHELL
- # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
- *v*x* | *x*v* ) as_opts=-vx ;;
- *v* ) as_opts=-v ;;
- *x* ) as_opts=-x ;;
- * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
- if test x$as_have_required = xno
-then :
- printf "%s\n" "$0: This script requires a shell more modern than all"
- printf "%s\n" "$0: the shells that I found on your system."
- if test ${ZSH_VERSION+y} ; then
- printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
- else
- printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
-$0: including any error possibly output before this
-$0: message. Then install a modern shell, or manually run
-$0: the script under such a shell if you do have one."
- fi
- exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-# as_fn_nop
-# ---------
-# Do nothing but, unlike ":", preserve the value of $?.
-as_fn_nop ()
-{
- return $?
-}
-as_nop=as_fn_nop
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
- as_lineno_1=$LINENO as_lineno_1a=$LINENO
- as_lineno_2=$LINENO as_lineno_2a=$LINENO
- eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
- test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
- # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
- sed -n '
- p
- /[$]LINENO/=
- ' <$as_myself |
- sed '
- s/[$]LINENO.*/&-/
- t lineno
- b
- :lineno
- N
- :loop
- s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
- t loop
- s/-\n.*//
- ' >$as_me.lineno &&
- chmod +x "$as_me.lineno" ||
- { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
- # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
- # already done that, so ensure we don't try to do so again and fall
- # in an infinite loop. This has already happened in practice.
- _as_can_reexec=no; export _as_can_reexec
- # Don't try to exec as it changes $[0], causing all sort of problems
- # (the dirname of $[0] is not the place where we might find the
- # original and so on. Autoconf is especially sensitive to this).
- . "./$as_me.lineno"
- # Exit status is that of the last command.
- exit
-}
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-
-test -n "$DJDIR" || exec 7<&0 &1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='sqlcipher'
-PACKAGE_TARNAME='sqlcipher'
-PACKAGE_VERSION='3.44.2'
-PACKAGE_STRING='sqlcipher 3.44.2'
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
-
-# Factoring default headers for most tests.
-ac_includes_default="\
-#include
-#ifdef HAVE_STDIO_H
-# include
-#endif
-#ifdef HAVE_STDLIB_H
-# include
-#endif
-#ifdef HAVE_STRING_H
-# include
-#endif
-#ifdef HAVE_INTTYPES_H
-# include
-#endif
-#ifdef HAVE_STDINT_H
-# include
-#endif
-#ifdef HAVE_STRINGS_H
-# include
-#endif
-#ifdef HAVE_SYS_TYPES_H
-# include
-#endif
-#ifdef HAVE_SYS_STAT_H
-# include
-#endif
-#ifdef HAVE_UNISTD_H
-# include
-#endif"
-
-ac_header_c_list=
-ac_subst_vars='LTLIBOBJS
-LIBOBJS
-BUILD_CFLAGS
-USE_GCOV
-OPT_FEATURE_FLAGS
-HAVE_ZLIB
-AMALGAMATION_LINE_MACROS
-amalgamation_line_macros
-USE_AMALGAMATION
-TARGET_DEBUG
-TARGET_HAVE_LINENOISE
-TARGET_HAVE_EDITLINE
-TARGET_HAVE_READLINE
-TARGET_READLINE_INC
-TARGET_READLINE_LIBS
-HAVE_TCL
-TCL_SHLIB_SUFFIX
-TCL_STUB_LIB_SPEC
-TCL_STUB_LIB_FLAG
-TCL_STUB_LIB_FILE
-TCL_LIB_SPEC
-TCL_LIB_FLAG
-TCL_LIB_FILE
-TCL_INCLUDE_SPEC
-TCL_SRC_DIR
-TCL_BIN_DIR
-TCL_VERSION
-TARGET_EXEEXT
-SQLITE_OS_WIN
-SQLITE_OS_UNIX
-BUILD_EXEEXT
-TEMP_STORE
-ALLOWRELEASE
-XTHREADCONNECT
-SQLITE_THREADSAFE
-BUILD_CC
-HAVE_WASI_SDK
-RELEASE
-VERSION
-program_prefix
-TCLLIBDIR
-TCLSH_CMD
-INSTALL_DATA
-INSTALL_SCRIPT
-INSTALL_PROGRAM
-LT_SYS_LIBRARY_PATH
-OTOOL64
-OTOOL
-LIPO
-NMEDIT
-DSYMUTIL
-MANIFEST_TOOL
-AWK
-RANLIB
-STRIP
-ac_ct_AR
-AR
-DLLTOOL
-OBJDUMP
-LN_S
-NM
-ac_ct_DUMPBIN
-DUMPBIN
-LD
-FGREP
-EGREP
-GREP
-SED
-OBJEXT
-EXEEXT
-ac_ct_CC
-CPPFLAGS
-LDFLAGS
-CFLAGS
-CC
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
-LIBTOOL
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-enable_shared
-enable_static
-with_pic
-enable_fast_install
-with_aix_soname
-with_gnu_ld
-with_sysroot
-enable_libtool_lock
-enable_largefile
-with_wasi_sdk
-enable_threadsafe
-with_crypto_lib
-enable_cross_thread_connections
-enable_releasemode
-enable_tempstore
-enable_tcl
-with_tcl
-enable_editline
-enable_readline
-with_readline_lib
-with_readline_inc
-with_linenoise
-enable_debug
-enable_amalgamation
-enable_load_extension
-enable_math
-enable_json
-enable_all
-enable_memsys5
-enable_memsys3
-enable_fts3
-enable_fts4
-enable_fts5
-enable_update_limit
-enable_geopoly
-enable_rtree
-enable_session
-enable_gcov
-'
- ac_precious_vars='build_alias
-host_alias
-target_alias
-CC
-CFLAGS
-LDFLAGS
-LIBS
-CPPFLAGS
-LT_SYS_LIBRARY_PATH
-TCLLIBDIR
-amalgamation_line_macros'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-datadir='${datarootdir}'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
- # If the previous option needs an argument, assign it.
- if test -n "$ac_prev"; then
- eval $ac_prev=\$ac_option
- ac_prev=
- continue
- fi
-
- case $ac_option in
- *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
- *=) ac_optarg= ;;
- *) ac_optarg=yes ;;
- esac
-
- case $ac_dashdash$ac_option in
- --)
- ac_dashdash=yes ;;
-
- -bindir | --bindir | --bindi | --bind | --bin | --bi)
- ac_prev=bindir ;;
- -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir=$ac_optarg ;;
-
- -build | --build | --buil | --bui | --bu)
- ac_prev=build_alias ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build_alias=$ac_optarg ;;
-
- -cache-file | --cache-file | --cache-fil | --cache-fi \
- | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
- ac_prev=cache_file ;;
- -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
- | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file=$ac_optarg ;;
-
- --config-cache | -C)
- cache_file=config.cache ;;
-
- -datadir | --datadir | --datadi | --datad)
- ac_prev=datadir ;;
- -datadir=* | --datadir=* | --datadi=* | --datad=*)
- datadir=$ac_optarg ;;
-
- -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
- | --dataroo | --dataro | --datar)
- ac_prev=datarootdir ;;
- -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
- | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
- datarootdir=$ac_optarg ;;
-
- -disable-* | --disable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=no ;;
-
- -docdir | --docdir | --docdi | --doc | --do)
- ac_prev=docdir ;;
- -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
- docdir=$ac_optarg ;;
-
- -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
- ac_prev=dvidir ;;
- -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
- dvidir=$ac_optarg ;;
-
- -enable-* | --enable-*)
- ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"enable_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval enable_$ac_useropt=\$ac_optarg ;;
-
- -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
- | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
- | --exec | --exe | --ex)
- ac_prev=exec_prefix ;;
- -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
- | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
- | --exec=* | --exe=* | --ex=*)
- exec_prefix=$ac_optarg ;;
-
- -gas | --gas | --ga | --g)
- # Obsolete; use --with-gas.
- with_gas=yes ;;
-
- -help | --help | --hel | --he | -h)
- ac_init_help=long ;;
- -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
- ac_init_help=recursive ;;
- -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
- ac_init_help=short ;;
-
- -host | --host | --hos | --ho)
- ac_prev=host_alias ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host_alias=$ac_optarg ;;
-
- -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
- ac_prev=htmldir ;;
- -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
- | --ht=*)
- htmldir=$ac_optarg ;;
-
- -includedir | --includedir | --includedi | --included | --include \
- | --includ | --inclu | --incl | --inc)
- ac_prev=includedir ;;
- -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
- | --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir=$ac_optarg ;;
-
- -infodir | --infodir | --infodi | --infod | --info | --inf)
- ac_prev=infodir ;;
- -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir=$ac_optarg ;;
-
- -libdir | --libdir | --libdi | --libd)
- ac_prev=libdir ;;
- -libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir=$ac_optarg ;;
-
- -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
- | --libexe | --libex | --libe)
- ac_prev=libexecdir ;;
- -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
- | --libexe=* | --libex=* | --libe=*)
- libexecdir=$ac_optarg ;;
-
- -localedir | --localedir | --localedi | --localed | --locale)
- ac_prev=localedir ;;
- -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
- localedir=$ac_optarg ;;
-
- -localstatedir | --localstatedir | --localstatedi | --localstated \
- | --localstate | --localstat | --localsta | --localst | --locals)
- ac_prev=localstatedir ;;
- -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
- | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
- localstatedir=$ac_optarg ;;
-
- -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
- ac_prev=mandir ;;
- -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir=$ac_optarg ;;
-
- -nfp | --nfp | --nf)
- # Obsolete; use --without-fp.
- with_fp=no ;;
-
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c | -n)
- no_create=yes ;;
-
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
- no_recursion=yes ;;
-
- -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
- | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
- | --oldin | --oldi | --old | --ol | --o)
- ac_prev=oldincludedir ;;
- -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
- | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
- | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir=$ac_optarg ;;
-
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- ac_prev=prefix ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix=$ac_optarg ;;
-
- -program-prefix | --program-prefix | --program-prefi | --program-pref \
- | --program-pre | --program-pr | --program-p)
- ac_prev=program_prefix ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix=$ac_optarg ;;
-
- -program-suffix | --program-suffix | --program-suffi | --program-suff \
- | --program-suf | --program-su | --program-s)
- ac_prev=program_suffix ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix=$ac_optarg ;;
-
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- \
- | --program-transform | --program-transfor \
- | --program-transfo | --program-transf \
- | --program-trans | --program-tran \
- | --progr-tra | --program-tr | --program-t)
- ac_prev=program_transform_name ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* \
- | --program-transfo=* | --program-transf=* \
- | --program-trans=* | --program-tran=* \
- | --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name=$ac_optarg ;;
-
- -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
- ac_prev=pdfdir ;;
- -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
- pdfdir=$ac_optarg ;;
-
- -psdir | --psdir | --psdi | --psd | --ps)
- ac_prev=psdir ;;
- -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
- psdir=$ac_optarg ;;
-
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- silent=yes ;;
-
- -runstatedir | --runstatedir | --runstatedi | --runstated \
- | --runstate | --runstat | --runsta | --runst | --runs \
- | --run | --ru | --r)
- ac_prev=runstatedir ;;
- -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
- | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
- | --run=* | --ru=* | --r=*)
- runstatedir=$ac_optarg ;;
-
- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
- ac_prev=sbindir ;;
- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
- | --sbi=* | --sb=*)
- sbindir=$ac_optarg ;;
-
- -sharedstatedir | --sharedstatedir | --sharedstatedi \
- | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
- | --sharedst | --shareds | --shared | --share | --shar \
- | --sha | --sh)
- ac_prev=sharedstatedir ;;
- -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
- | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
- | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
- | --sha=* | --sh=*)
- sharedstatedir=$ac_optarg ;;
-
- -site | --site | --sit)
- ac_prev=site ;;
- -site=* | --site=* | --sit=*)
- site=$ac_optarg ;;
-
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- ac_prev=srcdir ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir=$ac_optarg ;;
-
- -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
- | --syscon | --sysco | --sysc | --sys | --sy)
- ac_prev=sysconfdir ;;
- -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
- | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir=$ac_optarg ;;
-
- -target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target_alias ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target_alias=$ac_optarg ;;
-
- -v | -verbose | --verbose | --verbos | --verbo | --verb)
- verbose=yes ;;
-
- -version | --version | --versio | --versi | --vers | -V)
- ac_init_version=: ;;
-
- -with-* | --with-*)
- ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=\$ac_optarg ;;
-
- -without-* | --without-*)
- ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
- # Reject names that are not valid shell variable names.
- expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: \`$ac_useropt'"
- ac_useropt_orig=$ac_useropt
- ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
- case $ac_user_opts in
- *"
-"with_$ac_useropt"
-"*) ;;
- *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
- ac_unrecognized_sep=', ';;
- esac
- eval with_$ac_useropt=no ;;
-
- --x)
- # Obsolete; use --with-x.
- with_x=yes ;;
-
- -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
- | --x-incl | --x-inc | --x-in | --x-i)
- ac_prev=x_includes ;;
- -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
- | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes=$ac_optarg ;;
-
- -x-libraries | --x-libraries | --x-librarie | --x-librari \
- | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
- ac_prev=x_libraries ;;
- -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
- | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries=$ac_optarg ;;
-
- -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
- ;;
-
- *=*)
- ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
- # Reject names that are not valid shell variable names.
- case $ac_envvar in #(
- '' | [0-9]* | *[!_$as_cr_alnum]* )
- as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
- esac
- eval $ac_envvar=\$ac_optarg
- export $ac_envvar ;;
-
- *)
- # FIXME: should be removed in autoconf 3.0.
- printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
- expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
- : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
- ;;
-
- esac
-done
-
-if test -n "$ac_prev"; then
- ac_option=--`echo $ac_prev | sed 's/_/-/g'`
- as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
- case $enable_option_checking in
- no) ;;
- fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
- esac
-fi
-
-# Check all directory arguments for consistency.
-for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
- datadir sysconfdir sharedstatedir localstatedir includedir \
- oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir runstatedir
-do
- eval ac_val=\$$ac_var
- # Remove trailing slashes.
- case $ac_val in
- */ )
- ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
- eval $ac_var=\$ac_val;;
- esac
- # Be sure to have absolute directory names.
- case $ac_val in
- [\\/$]* | ?:[\\/]* ) continue;;
- NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
- esac
- as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
- if test "x$build_alias" = x; then
- cross_compiling=maybe
- elif test "x$build_alias" != "x$host_alias"; then
- cross_compiling=yes
- fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
- as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
- as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
- ac_srcdir_defaulted=yes
- # Try the directory containing this script, then the parent directory.
- ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_myself" : 'X\(//\)[^/]' \| \
- X"$as_myself" : 'X\(//\)$' \| \
- X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_myself" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- srcdir=$ac_confdir
- if test ! -r "$srcdir/$ac_unique_file"; then
- srcdir=..
- fi
-else
- ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
- test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
- as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
- cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
- pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
- srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
- eval ac_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_env_${ac_var}_value=\$${ac_var}
- eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
- eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat <<_ACEOF
-\`configure' configures sqlcipher 3.44.2 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE. See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
- -h, --help display this help and exit
- --help=short display options specific to this package
- --help=recursive display the short help of all the included packages
- -V, --version display version information and exit
- -q, --quiet, --silent do not print \`checking ...' messages
- --cache-file=FILE cache test results in FILE [disabled]
- -C, --config-cache alias for \`--cache-file=config.cache'
- -n, --no-create do not create output files
- --srcdir=DIR find the sources in DIR [configure dir or \`..']
-
-Installation directories:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
- --bindir=DIR user executables [EPREFIX/bin]
- --sbindir=DIR system admin executables [EPREFIX/sbin]
- --libexecdir=DIR program executables [EPREFIX/libexec]
- --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data [PREFIX/var]
- --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
- --libdir=DIR object code libraries [EPREFIX/lib]
- --includedir=DIR C header files [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc [/usr/include]
- --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
- --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
- --infodir=DIR info documentation [DATAROOTDIR/info]
- --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
- --mandir=DIR man documentation [DATAROOTDIR/man]
- --docdir=DIR documentation root [DATAROOTDIR/doc/sqlcipher]
- --htmldir=DIR html documentation [DOCDIR]
- --dvidir=DIR dvi documentation [DOCDIR]
- --pdfdir=DIR pdf documentation [DOCDIR]
- --psdir=DIR ps documentation [DOCDIR]
-_ACEOF
-
- cat <<\_ACEOF
-
-System types:
- --build=BUILD configure for building on BUILD [guessed]
- --host=HOST cross-compile to build programs to run on HOST [BUILD]
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
- case $ac_init_help in
- short | recursive ) echo "Configuration of sqlcipher 3.44.2:";;
- esac
- cat <<\_ACEOF
-
-Optional Features:
- --disable-option-checking ignore unrecognized --enable/--with options
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --enable-shared[=PKGS] build shared libraries [default=yes]
- --enable-static[=PKGS] build static libraries [default=yes]
- --enable-fast-install[=PKGS]
- optimize for fast installation [default=yes]
- --disable-libtool-lock avoid locking (might break parallel builds)
- --disable-largefile omit support for large files
- --disable-threadsafe Disable mutexing
- --enable-cross-thread-connections
- Allow connection sharing across threads
- --enable-releasemode Support libtool link to release mode
- --enable-tempstore Use an in-ram database for temporary tables
- (never,no,yes,always)
- --disable-tcl do not build TCL extension
- --enable-editline enable BSD editline support
- --disable-readline disable readline support
- --enable-debug enable debugging & verbose explain
- --disable-amalgamation Disable the amalgamation and instead build all files
- separately
- --disable-load-extension
- Disable loading of external extensions
- --disable-math Disable math functions
- --disable-json Disable JSON functions
- --enable-all Enable FTS4, FTS5, Geopoly, RTree, Sessions
- --enable-memsys5 Enable MEMSYS5
- --enable-memsys3 Enable MEMSYS3
- --enable-fts3 Enable the FTS3 extension
- --enable-fts4 Enable the FTS4 extension
- --enable-fts5 Enable the FTS5 extension
- --enable-update-limit Enable the UPDATE/DELETE LIMIT clause
- --enable-geopoly Enable the GEOPOLY extension
- --enable-rtree Enable the RTREE extension
- --enable-session Enable the SESSION extension
- --enable-gcov Enable coverage testing using gcov
-
-Optional Packages:
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
- both]
- --with-aix-soname=aix|svr4|both
- shared library versioning (aka "SONAME") variant to
- provide on AIX, [default=aix].
- --with-gnu-ld assume the C compiler uses GNU ld [default=no]
- --with-sysroot[=DIR] Search for dependent libraries within DIR (or the
- compiler's sysroot if not specified).
- --with-wasi-sdk=DIR directory containing the WASI SDK. Triggers
- cross-compile to WASM.
- --with-crypto-lib Specify which crypto library to use
- --with-tcl=DIR directory containing tcl configuration
- (tclConfig.sh)
- --with-readline-lib specify readline library
- --with-readline-inc specify readline include paths
- --with-linenoise=DIR source directory for linenoise library
-
-Some influential environment variables:
- CC C compiler command
- CFLAGS C compiler flags
- LDFLAGS linker flags, e.g. -L if you have libraries in a
- nonstandard directory
- LIBS libraries to pass to the linker, e.g. -l
- CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if
- you have headers in a nonstandard directory
- LT_SYS_LIBRARY_PATH
- User-defined run-time library search path.
- TCLLIBDIR Where to install tcl plugin
- amalgamation_line_macros
-
-
-Use these variables to override the choices made by `configure' or to help
-it to find libraries and programs with nonstandard names/locations.
-
-Report bugs to the package provider.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
- # If there are subdirs, report their specific --help.
- for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
- test -d "$ac_dir" ||
- { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
- continue
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
- cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for configure.gnu first; this name is used for a wrapper for
- # Metaconfig's "Configure" on case-insensitive file systems.
- if test -f "$ac_srcdir/configure.gnu"; then
- echo &&
- $SHELL "$ac_srcdir/configure.gnu" --help=recursive
- elif test -f "$ac_srcdir/configure"; then
- echo &&
- $SHELL "$ac_srcdir/configure" --help=recursive
- else
- printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
- fi || ac_status=$?
- cd "$ac_pwd" || { ac_status=$?; break; }
- done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
- cat <<\_ACEOF
-sqlcipher configure 3.44.2
-generated by GNU Autoconf 2.71
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
- exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-
-# ac_fn_c_try_compile LINENO
-# --------------------------
-# Try to compile conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam
- if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest.$ac_objext
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_compile
-
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- grep -v '^ *+' conftest.err >conftest.er1
- cat conftest.er1 >&5
- mv -f conftest.er1 conftest.err
- fi
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && {
- test -z "$ac_c_werror_flag" ||
- test ! -s conftest.err
- } && test -s conftest$ac_exeext && {
- test "$cross_compiling" = yes ||
- test -x conftest$ac_exeext
- }
-then :
- ac_retval=0
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=1
-fi
- # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
- # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
- # interfere with the next link command; also delete a directory that is
- # left behind by Apple's compiler. We do this before executing the actions.
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_link
-
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_compile
-
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-/* Define $2 to an innocuous variant, in case declares $2.
- For example, HP-UX 11i declares gettimeofday. */
-#define $2 innocuous_$2
-
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $2 (); below. */
-
-#include
-#undef $2
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char $2 ();
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined __stub_$2 || defined __stub___$2
-choke me
-#endif
-
-int
-main (void)
-{
-return $2 ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- eval "$3=yes"
-else $as_nop
- eval "$3=no"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_func
-
-# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
-# -------------------------------------------
-# Tests whether TYPE exists after having included INCLUDES, setting cache
-# variable VAR accordingly.
-ac_fn_c_check_type ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-printf %s "checking for $2... " >&6; }
-if eval test \${$3+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- eval "$3=no"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-if (sizeof ($2))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-int
-main (void)
-{
-if (sizeof (($2)))
- return 0;
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- eval "$3=yes"
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-eval ac_res=\$$3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_type
-ac_configure_args_raw=
-for ac_arg
-do
- case $ac_arg in
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append ac_configure_args_raw " '$ac_arg'"
-done
-
-case $ac_configure_args_raw in
- *$as_nl*)
- ac_safe_unquote= ;;
- *)
- ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
- ac_unsafe_a="$ac_unsafe_z#~"
- ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
- ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
-esac
-
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by sqlcipher $as_me 3.44.2, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- $ $0$ac_configure_args_raw
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
-
-/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
-/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
-/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- printf "%s\n" "PATH: $as_dir"
- done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
- for ac_arg
- do
- case $ac_arg in
- -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil)
- continue ;;
- *\'*)
- ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- case $ac_pass in
- 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
- 2)
- as_fn_append ac_configure_args1 " '$ac_arg'"
- if test $ac_must_keep_next = true; then
- ac_must_keep_next=false # Got value, back to normal.
- else
- case $ac_arg in
- *=* | --config-cache | -C | -disable-* | --disable-* \
- | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
- | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
- | -with-* | --with-* | -without-* | --without-* | --x)
- case "$ac_configure_args0 " in
- "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
- esac
- ;;
- -* ) ac_must_keep_next=true ;;
- esac
- fi
- as_fn_append ac_configure_args " '$ac_arg'"
- ;;
- esac
- done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log. We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
- # Sanitize IFS.
- IFS=" "" $as_nl"
- # Save into config.log some information that might help in debugging.
- {
- echo
-
- printf "%s\n" "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
- echo
- # The following way of writing the cache mishandles newlines in values,
-(
- for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
- (set) 2>&1 |
- case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- sed -n \
- "s/'\''/'\''\\\\'\'''\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
- ;; #(
- *)
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-)
- echo
-
- printf "%s\n" "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
- echo
- for ac_var in $ac_subst_vars
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
-
- if test -n "$ac_subst_files"; then
- printf "%s\n" "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
- echo
- for ac_var in $ac_subst_files
- do
- eval ac_val=\$$ac_var
- case $ac_val in
- *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
- esac
- printf "%s\n" "$ac_var='\''$ac_val'\''"
- done | sort
- echo
- fi
-
- if test -s confdefs.h; then
- printf "%s\n" "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
- echo
- cat confdefs.h
- echo
- fi
- test "$ac_signal" != 0 &&
- printf "%s\n" "$as_me: caught signal $ac_signal"
- printf "%s\n" "$as_me: exit $exit_status"
- } >&5
- rm -f core *.core core.conftest.* &&
- rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
- exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
- trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-printf "%s\n" "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-
-printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-if test -n "$CONFIG_SITE"; then
- ac_site_files="$CONFIG_SITE"
-elif test "x$prefix" != xNONE; then
- ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
-else
- ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
-fi
-
-for ac_site_file in $ac_site_files
-do
- case $ac_site_file in #(
- */*) :
- ;; #(
- *) :
- ac_site_file=./$ac_site_file ;;
-esac
- if test -f "$ac_site_file" && test -r "$ac_site_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
- sed 's/^/| /' "$ac_site_file" >&5
- . "$ac_site_file" \
- || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
- fi
-done
-
-if test -r "$cache_file"; then
- # Some versions of bash will fail to source /dev/null (special files
- # actually), so we avoid doing that. DJGPP emulates it as a regular file.
- if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
- case $cache_file in
- [\\/]* | ?:[\\/]* ) . "$cache_file";;
- *) . "./$cache_file";;
- esac
- fi
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
- >$cache_file
-fi
-
-# Test code for whether the C compiler supports C89 (global declarations)
-ac_c_conftest_c89_globals='
-/* Does the compiler advertise C89 conformance?
- Do not test the value of __STDC__, because some compilers set it to 0
- while being otherwise adequately conformant. */
-#if !defined __STDC__
-# error "Compiler does not advertise C89 conformance"
-#endif
-
-#include
-#include
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */
-struct buf { int x; };
-struct buf * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not \xHH hex character constants.
- These do not provoke an error unfortunately, instead are silently treated
- as an "x". The following induces an error, until -std is added to get
- proper ANSI mode. Curiously \x00 != x always comes out true, for an
- array size at least. It is necessary to write \x00 == 0 to get something
- that is true only with -std. */
-int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1];
-
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) '\''x'\''
-int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),
- int, int);'
-
-# Test code for whether the C compiler supports C89 (body of main).
-ac_c_conftest_c89_main='
-ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]);
-'
-
-# Test code for whether the C compiler supports C99 (global declarations)
-ac_c_conftest_c99_globals='
-// Does the compiler advertise C99 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
-# error "Compiler does not advertise C99 conformance"
-#endif
-
-#include
-extern int puts (const char *);
-extern int printf (const char *, ...);
-extern int dprintf (int, const char *, ...);
-extern void *malloc (size_t);
-
-// Check varargs macros. These examples are taken from C99 6.10.3.5.
-// dprintf is used instead of fprintf to avoid needing to declare
-// FILE and stderr.
-#define debug(...) dprintf (2, __VA_ARGS__)
-#define showlist(...) puts (#__VA_ARGS__)
-#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
-static void
-test_varargs_macros (void)
-{
- int x = 1234;
- int y = 5678;
- debug ("Flag");
- debug ("X = %d\n", x);
- showlist (The first, second, and third items.);
- report (x>y, "x is %d but y is %d", x, y);
-}
-
-// Check long long types.
-#define BIG64 18446744073709551615ull
-#define BIG32 4294967295ul
-#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
-#if !BIG_OK
- #error "your preprocessor is broken"
-#endif
-#if BIG_OK
-#else
- #error "your preprocessor is broken"
-#endif
-static long long int bignum = -9223372036854775807LL;
-static unsigned long long int ubignum = BIG64;
-
-struct incomplete_array
-{
- int datasize;
- double data[];
-};
-
-struct named_init {
- int number;
- const wchar_t *name;
- double average;
-};
-
-typedef const char *ccp;
-
-static inline int
-test_restrict (ccp restrict text)
-{
- // See if C++-style comments work.
- // Iterate through items via the restricted pointer.
- // Also check for declarations in for loops.
- for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i)
- continue;
- return 0;
-}
-
-// Check varargs and va_copy.
-static bool
-test_varargs (const char *format, ...)
-{
- va_list args;
- va_start (args, format);
- va_list args_copy;
- va_copy (args_copy, args);
-
- const char *str = "";
- int number = 0;
- float fnumber = 0;
-
- while (*format)
- {
- switch (*format++)
- {
- case '\''s'\'': // string
- str = va_arg (args_copy, const char *);
- break;
- case '\''d'\'': // int
- number = va_arg (args_copy, int);
- break;
- case '\''f'\'': // float
- fnumber = va_arg (args_copy, double);
- break;
- default:
- break;
- }
- }
- va_end (args_copy);
- va_end (args);
-
- return *str && number && fnumber;
-}
-'
-
-# Test code for whether the C compiler supports C99 (body of main).
-ac_c_conftest_c99_main='
- // Check bool.
- _Bool success = false;
- success |= (argc != 0);
-
- // Check restrict.
- if (test_restrict ("String literal") == 0)
- success = true;
- char *restrict newvar = "Another string";
-
- // Check varargs.
- success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234);
- test_varargs_macros ();
-
- // Check flexible array members.
- struct incomplete_array *ia =
- malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
- ia->datasize = 10;
- for (int i = 0; i < ia->datasize; ++i)
- ia->data[i] = i * 1.234;
-
- // Check named initializers.
- struct named_init ni = {
- .number = 34,
- .name = L"Test wide string",
- .average = 543.34343,
- };
-
- ni.number = 58;
-
- int dynamic_array[ni.number];
- dynamic_array[0] = argv[0][0];
- dynamic_array[ni.number - 1] = 543;
-
- // work around unused variable warnings
- ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\''
- || dynamic_array[ni.number - 1] != 543);
-'
-
-# Test code for whether the C compiler supports C11 (global declarations)
-ac_c_conftest_c11_globals='
-// Does the compiler advertise C11 conformance?
-#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
-# error "Compiler does not advertise C11 conformance"
-#endif
-
-// Check _Alignas.
-char _Alignas (double) aligned_as_double;
-char _Alignas (0) no_special_alignment;
-extern char aligned_as_int;
-char _Alignas (0) _Alignas (int) aligned_as_int;
-
-// Check _Alignof.
-enum
-{
- int_alignment = _Alignof (int),
- int_array_alignment = _Alignof (int[100]),
- char_alignment = _Alignof (char)
-};
-_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-
-// Check _Noreturn.
-int _Noreturn does_not_return (void) { for (;;) continue; }
-
-// Check _Static_assert.
-struct test_static_assert
-{
- int x;
- _Static_assert (sizeof (int) <= sizeof (long int),
- "_Static_assert does not work in struct");
- long int y;
-};
-
-// Check UTF-8 literals.
-#define u8 syntax error!
-char const utf8_literal[] = u8"happens to be ASCII" "another string";
-
-// Check duplicate typedefs.
-typedef long *long_ptr;
-typedef long int *long_ptr;
-typedef long_ptr long_ptr;
-
-// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
-struct anonymous
-{
- union {
- struct { int i; int j; };
- struct { int k; long int l; } w;
- };
- int m;
-} v1;
-'
-
-# Test code for whether the C compiler supports C11 (body of main).
-ac_c_conftest_c11_main='
- _Static_assert ((offsetof (struct anonymous, i)
- == offsetof (struct anonymous, w.k)),
- "Anonymous union alignment botch");
- v1.i = 2;
- v1.w.k = 5;
- ok |= v1.i != 5;
-'
-
-# Test code for whether the C compiler supports C11 (complete).
-ac_c_conftest_c11_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-${ac_c_conftest_c11_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- ${ac_c_conftest_c11_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C99 (complete).
-ac_c_conftest_c99_program="${ac_c_conftest_c89_globals}
-${ac_c_conftest_c99_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- ${ac_c_conftest_c99_main}
- return ok;
-}
-"
-
-# Test code for whether the C compiler supports C89 (complete).
-ac_c_conftest_c89_program="${ac_c_conftest_c89_globals}
-
-int
-main (int argc, char **argv)
-{
- int ok = 0;
- ${ac_c_conftest_c89_main}
- return ok;
-}
-"
-
-as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H"
-as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H"
-as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H"
-as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
-as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
-as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
-as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
-as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
-as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
-
-# Auxiliary files required by this configure script.
-ac_aux_files="install-sh config.guess config.sub ltmain.sh"
-
-# Locations in which to look for auxiliary files.
-ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.."
-
-# Search for a directory containing all of the required auxiliary files,
-# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
-# If we don't find one directory that contains all the files we need,
-# we report the set of missing files from the *first* directory in
-# $ac_aux_dir_candidates and give up.
-ac_missing_aux_files=""
-ac_first_candidate=:
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in $ac_aux_dir_candidates
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- as_found=:
-
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
- ac_aux_dir_found=yes
- ac_install_sh=
- for ac_aux in $ac_aux_files
- do
- # As a special case, if "install-sh" is required, that requirement
- # can be satisfied by any of "install-sh", "install.sh", or "shtool",
- # and $ac_install_sh is set appropriately for whichever one is found.
- if test x"$ac_aux" = x"install-sh"
- then
- if test -f "${as_dir}install-sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
- ac_install_sh="${as_dir}install-sh -c"
- elif test -f "${as_dir}install.sh"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
- ac_install_sh="${as_dir}install.sh -c"
- elif test -f "${as_dir}shtool"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
- ac_install_sh="${as_dir}shtool install -c"
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} install-sh"
- else
- break
- fi
- fi
- else
- if test -f "${as_dir}${ac_aux}"; then
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
- else
- ac_aux_dir_found=no
- if $ac_first_candidate; then
- ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
- else
- break
- fi
- fi
- fi
- done
- if test "$ac_aux_dir_found" = yes; then
- ac_aux_dir="$as_dir"
- break
- fi
- ac_first_candidate=false
-
- as_found=false
-done
-IFS=$as_save_IFS
-if $as_found
-then :
-
-else $as_nop
- as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5
-fi
-
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-if test -f "${ac_aux_dir}config.guess"; then
- ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
-fi
-if test -f "${ac_aux_dir}config.sub"; then
- ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
-fi
-if test -f "$ac_aux_dir/configure"; then
- ac_configure="$SHELL ${ac_aux_dir}configure"
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
- eval ac_old_set=\$ac_cv_env_${ac_var}_set
- eval ac_new_set=\$ac_env_${ac_var}_set
- eval ac_old_val=\$ac_cv_env_${ac_var}_value
- eval ac_new_val=\$ac_env_${ac_var}_value
- case $ac_old_set,$ac_new_set in
- set,)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,set)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
- ac_cache_corrupted=: ;;
- ,);;
- *)
- if test "x$ac_old_val" != "x$ac_new_val"; then
- # differences in whitespace do not lead to failure.
- ac_old_val_w=`echo x $ac_old_val`
- ac_new_val_w=`echo x $ac_new_val`
- if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
- ac_cache_corrupted=:
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
- eval $ac_var=\$ac_old_val
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
- fi;;
- esac
- # Pass precious variables to config.status.
- if test "$ac_new_set" = set; then
- case $ac_new_val in
- *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
- *) ac_arg=$ac_var=$ac_new_val ;;
- esac
- case " $ac_configure_args " in
- *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
- *) as_fn_append ac_configure_args " '$ac_arg'" ;;
- esac
- fi
-done
-if $ac_cache_corrupted; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
- and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'`
-if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then
-as_fn_error $? "configure script is out of date:
- configure \$PACKAGE_VERSION = $PACKAGE_VERSION
- top level VERSION file = $sqlite_version_sanity_check
-please regen with autoconf" "$LINENO" 5
-fi
-
-#########
-# Programs needed
-#
-
-
-case `pwd` in
- *\ * | *\ *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-printf "%s\n" "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
-esac
-
-
-
-macro_version='2.4.6'
-macro_revision='2.4.6'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ltmain=$ac_aux_dir/ltmain.sh
-
-
-
- # Make sure we can run config.sub.
-$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-printf %s "checking build system type... " >&6; }
-if test ${ac_cv_build+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-printf "%s\n" "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-printf %s "checking host system type... " >&6; }
-if test ${ac_cv_host+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` ||
- as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-printf "%s\n" "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
-
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-
-ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-printf %s "checking how to print strings... " >&6; }
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
- test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
- ECHO='printf %s\n'
-else
- # Use this function as a fallback that always works.
- func_fallback_echo ()
- {
- eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
- }
- ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
- $ECHO ""
-}
-
-case $ECHO in
- printf*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-printf "%s\n" "printf" >&6; } ;;
- print*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-printf "%s\n" "print -r" >&6; } ;;
- *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-printf "%s\n" "cat" >&6; } ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- fi
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl.exe
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_CC" && break
-done
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
-set dummy ${ac_tool_prefix}clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}clang"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-printf "%s\n" "$CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "clang", so it can be a program name with args.
-set dummy clang; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="clang"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-printf "%s\n" "$ac_ct_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-fi
-
-
-test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
-
-# Provide some information about the compiler.
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion -version; do
- { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- sed '10a\
-... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
- cat conftest.er1 >&5
- fi
- rm -f conftest.er1 conftest.err
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
-# Try to create an executable without -o first, disregard a.out.
-# It will help us diagnose broken compilers, and finding out an intuition
-# of exeext.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-printf %s "checking whether the C compiler works... " >&6; }
-ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-
-# The possible output files:
-ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
-
-ac_rmfiles=
-for ac_file in $ac_files
-do
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- * ) ac_rmfiles="$ac_rmfiles $ac_file";;
- esac
-done
-rm -f $ac_rmfiles
-
-if { { ac_try="$ac_link_default"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link_default") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
-# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
-# in a Makefile. We should not override ac_cv_exeext if it was cached,
-# so that the user can short-circuit this test for compilers unknown to
-# Autoconf.
-for ac_file in $ac_files ''
-do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
- ;;
- [ab].out )
- # We found the default executable, but exeext='' is most
- # certainly right.
- break;;
- *.* )
- if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
- then :; else
- ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- fi
- # We set ac_cv_exeext here because the later test for it is not
- # safe: cross compilers may not add the suffix if given an `-o'
- # argument, so we may need to know it at that point already.
- # Even if this section looks crufty: it has the advantage of
- # actually working.
- break;;
- * )
- break;;
- esac
-done
-test "$ac_cv_exeext" = no && ac_cv_exeext=
-
-else $as_nop
- ac_file=''
-fi
-if test -z "$ac_file"
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "C compiler cannot create executables
-See \`config.log' for more details" "$LINENO" 5; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-printf %s "checking for C compiler default output file name... " >&6; }
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-printf "%s\n" "$ac_file" >&6; }
-ac_exeext=$ac_cv_exeext
-
-rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-printf %s "checking for suffix of executables... " >&6; }
-if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- # If both `conftest.exe' and `conftest' are `present' (well, observable)
-# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
-# work properly (i.e., refer to `conftest.exe'), while it won't with
-# `rm'.
-for ac_file in conftest.exe conftest conftest.*; do
- test -f "$ac_file" || continue
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
- *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
- break;;
- * ) break;;
- esac
-done
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest conftest$ac_cv_exeext
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-printf "%s\n" "$ac_cv_exeext" >&6; }
-
-rm -f conftest.$ac_ext
-EXEEXT=$ac_cv_exeext
-ac_exeext=$EXEEXT
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include
-int
-main (void)
-{
-FILE *f = fopen ("conftest.out", "w");
- return ferror (f) || fclose (f) != 0;
-
- ;
- return 0;
-}
-_ACEOF
-ac_clean_files="$ac_clean_files conftest.out"
-# Check that the compiler produces executables we can run. If not, either
-# the compiler is broken, or we cross compile.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-printf %s "checking whether we are cross compiling... " >&6; }
-if test "$cross_compiling" != yes; then
- { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if { ac_try='./conftest$ac_cv_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then
- cross_compiling=no
- else
- if test "$cross_compiling" = maybe; then
- cross_compiling=yes
- else
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error 77 "cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details" "$LINENO" 5; }
- fi
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-printf "%s\n" "$cross_compiling" >&6; }
-
-rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
-ac_clean_files=$ac_clean_files_save
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-printf %s "checking for suffix of object files... " >&6; }
-if test ${ac_cv_objext+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-rm -f conftest.o conftest.obj
-if { { ac_try="$ac_compile"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-printf "%s\n" "$ac_try_echo"; } >&5
- (eval "$ac_compile") 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-then :
- for ac_file in conftest.o conftest.obj conftest.*; do
- test -f "$ac_file" || continue;
- case $ac_file in
- *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
- *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
- break;;
- esac
-done
-else $as_nop
- printf "%s\n" "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compute suffix of object files: cannot compile
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-rm -f conftest.$ac_cv_objext conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-printf "%s\n" "$ac_cv_objext" >&6; }
-OBJEXT=$ac_cv_objext
-ac_objext=$OBJEXT
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
-printf %s "checking whether the compiler supports GNU C... " >&6; }
-if test ${ac_cv_c_compiler_gnu+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_compiler_gnu=yes
-else $as_nop
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+y}
-ac_save_CFLAGS=$CFLAGS
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-printf %s "checking whether $CC accepts -g... " >&6; }
-if test ${ac_cv_prog_cc_g+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_save_c_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag=yes
- ac_cv_prog_cc_g=no
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-else $as_nop
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-
-else $as_nop
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
-if test $ac_test_CFLAGS; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-ac_prog_cc_stdc=no
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
-printf %s "checking for $CC option to enable C11 features... " >&6; }
-if test ${ac_cv_prog_cc_c11+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c11=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c11_program
-_ACEOF
-for ac_arg in '' -std=gnu11
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c11=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c11" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c11" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c11" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
- CC="$CC $ac_cv_prog_cc_c11"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
- ac_prog_cc_stdc=c11
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
-printf %s "checking for $CC option to enable C99 features... " >&6; }
-if test ${ac_cv_prog_cc_c99+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c99=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c99_program
-_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c99=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c99" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c99" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c99" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
- CC="$CC $ac_cv_prog_cc_c99"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
- ac_prog_cc_stdc=c99
-fi
-fi
-if test x$ac_prog_cc_stdc = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
-printf %s "checking for $CC option to enable C89 features... " >&6; }
-if test ${ac_cv_prog_cc_c89+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$ac_c_conftest_c89_program
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-
-if test "x$ac_cv_prog_cc_c89" = xno
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; }
-else $as_nop
- if test "x$ac_cv_prog_cc_c89" = x
-then :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; }
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
- CC="$CC $ac_cv_prog_cc_c89"
-fi
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
- ac_prog_cc_stdc=c89
-fi
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
-printf %s "checking for a sed that does not truncate output... " >&6; }
-if test ${ac_cv_path_SED+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
- for ac_i in 1 2 3 4 5 6 7; do
- ac_script="$ac_script$as_nl$ac_script"
- done
- echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
- { ac_script=; unset ac_script;}
- if test -z "$SED"; then
- ac_path_SED_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in sed gsed
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_SED="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_SED" || continue
-# Check for GNU ac_path_SED and select it if it is found.
- # Check for GNU $ac_path_SED
-case `"$ac_path_SED" --version 2>&1` in
-*GNU*)
- ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" '' >> "conftest.nl"
- "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_SED_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_SED="$ac_path_SED"
- ac_path_SED_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_SED_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_SED"; then
- as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
- fi
-else
- ac_cv_path_SED=$SED
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
-printf "%s\n" "$ac_cv_path_SED" >&6; }
- SED="$ac_cv_path_SED"
- rm -f conftest.sed
-
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-printf %s "checking for grep that handles long lines and -e... " >&6; }
-if test ${ac_cv_path_GREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$GREP"; then
- ac_path_GREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in grep ggrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-printf "%s\n" "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-printf %s "checking for egrep... " >&6; }
-if test ${ac_cv_path_EGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in egrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-printf "%s\n" "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
-printf %s "checking for fgrep... " >&6; }
-if test ${ac_cv_path_FGREP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
- then ac_cv_path_FGREP="$GREP -F"
- else
- if test -z "$FGREP"; then
- ac_path_FGREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in fgrep
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_FGREP="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_FGREP" || continue
-# Check for GNU ac_path_FGREP and select it if it is found.
- # Check for GNU $ac_path_FGREP
-case `"$ac_path_FGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
-*)
- ac_count=0
- printf %s 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- printf "%s\n" 'FGREP' >> "conftest.nl"
- "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_FGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_FGREP="$ac_path_FGREP"
- ac_path_FGREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_FGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_FGREP"; then
- as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_FGREP=$FGREP
-fi
-
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
-printf "%s\n" "$ac_cv_path_FGREP" >&6; }
- FGREP="$ac_cv_path_FGREP"
-
-
-test -z "$GREP" && GREP=grep
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-gnu-ld was given.
-if test ${with_gnu_ld+y}
-then :
- withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
-else $as_nop
- with_gnu_ld=no
-fi
-
-ac_prog=ld
-if test yes = "$GCC"; then
- # Check if gcc -print-prog-name=ld gives a path.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-printf %s "checking for ld used by $CC... " >&6; }
- case $host in
- *-*-mingw*)
- # gcc leaves a trailing carriage return, which upsets mingw
- ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
- *)
- ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
- esac
- case $ac_prog in
- # Accept absolute paths.
- [\\/]* | ?:[\\/]*)
- re_direlt='/[^/][^/]*/\.\./'
- # Canonicalize the pathname of ld
- ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
- while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
- ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
- done
- test -z "$LD" && LD=$ac_prog
- ;;
- "")
- # If it fails, then pretend we aren't using GCC.
- ac_prog=ld
- ;;
- *)
- # If it is relative, then search for the first ld in PATH.
- with_gnu_ld=unknown
- ;;
- esac
-elif test yes = "$with_gnu_ld"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-printf %s "checking for GNU ld... " >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-printf %s "checking for non-GNU ld... " >&6; }
-fi
-if test ${lt_cv_path_LD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -z "$LD"; then
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
- lt_cv_path_LD=$ac_dir/$ac_prog
- # Check to see if the program is GNU ld. I'd rather use --version,
- # but apparently some variants of GNU ld only accept -v.
- # Break only if it was the GNU/non-GNU ld that we prefer.
- case `"$lt_cv_path_LD" -v 2>&1 &5
-printf "%s\n" "$LD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-printf %s "checking if the linker ($LD) is GNU ld... " >&6; }
-if test ${lt_cv_prog_gnu_ld+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- # I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 &5
-printf "%s\n" "$lt_cv_prog_gnu_ld" >&6; }
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
-printf %s "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
-if test ${lt_cv_path_NM+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$NM"; then
- # Let the user override the test.
- lt_cv_path_NM=$NM
-else
- lt_nm_to_check=${ac_tool_prefix}nm
- if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
- lt_nm_to_check="$lt_nm_to_check nm"
- fi
- for lt_tmp_nm in $lt_nm_to_check; do
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- tmp_nm=$ac_dir/$lt_tmp_nm
- if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
- # Check to see if the nm accepts a BSD-compat flag.
- # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
- # nm: unknown option "B" ignored
- # Tru64's nm complains that /dev/null is an invalid object file
- # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
- case $build_os in
- mingw*) lt_bad_file=conftest.nm/nofile ;;
- *) lt_bad_file=/dev/null ;;
- esac
- case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
- *$lt_bad_file* | *'Invalid file or object type'*)
- lt_cv_path_NM="$tmp_nm -B"
- break 2
- ;;
- *)
- case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
- */dev/null*)
- lt_cv_path_NM="$tmp_nm -p"
- break 2
- ;;
- *)
- lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
- continue # so that we can try to find one that supports BSD flags
- ;;
- esac
- ;;
- esac
- fi
- done
- IFS=$lt_save_ifs
- done
- : ${lt_cv_path_NM=no}
-fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
-printf "%s\n" "$lt_cv_path_NM" >&6; }
-if test no != "$lt_cv_path_NM"; then
- NM=$lt_cv_path_NM
-else
- # Didn't find any BSD compatible name lister, look for dumpbin.
- if test -n "$DUMPBIN"; then :
- # Let the user override the test.
- else
- if test -n "$ac_tool_prefix"; then
- for ac_prog in dumpbin "link -dump"
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DUMPBIN+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$DUMPBIN"; then
- ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-DUMPBIN=$ac_cv_prog_DUMPBIN
-if test -n "$DUMPBIN"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
-printf "%s\n" "$DUMPBIN" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$DUMPBIN" && break
- done
-fi
-if test -z "$DUMPBIN"; then
- ac_ct_DUMPBIN=$DUMPBIN
- for ac_prog in dumpbin "link -dump"
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DUMPBIN+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_DUMPBIN"; then
- ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
-if test -n "$ac_ct_DUMPBIN"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
-printf "%s\n" "$ac_ct_DUMPBIN" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_DUMPBIN" && break
-done
-
- if test "x$ac_ct_DUMPBIN" = x; then
- DUMPBIN=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- DUMPBIN=$ac_ct_DUMPBIN
- fi
-fi
-
- case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
- *COFF*)
- DUMPBIN="$DUMPBIN -symbols -headers"
- ;;
- *)
- DUMPBIN=:
- ;;
- esac
- fi
-
- if test : != "$DUMPBIN"; then
- NM=$DUMPBIN
- fi
-fi
-test -z "$NM" && NM=nm
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
-printf %s "checking the name lister ($NM) interface... " >&6; }
-if test ${lt_cv_nm_interface+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_nm_interface="BSD nm"
- echo "int some_variable = 0;" > conftest.$ac_ext
- (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
- (eval "$ac_compile" 2>conftest.err)
- cat conftest.err >&5
- (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
- (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
- cat conftest.err >&5
- (eval echo "\"\$as_me:$LINENO: output\"" >&5)
- cat conftest.out >&5
- if $GREP 'External.*some_variable' conftest.out > /dev/null; then
- lt_cv_nm_interface="MS dumpbin"
- fi
- rm -f conftest*
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
-printf "%s\n" "$lt_cv_nm_interface" >&6; }
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
-printf %s "checking whether ln -s works... " >&6; }
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-printf "%s\n" "no, using $LN_S" >&6; }
-fi
-
-# find the maximum length of command line arguments
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
-printf %s "checking the maximum length of command line arguments... " >&6; }
-if test ${lt_cv_sys_max_cmd_len+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- i=0
- teststring=ABCD
-
- case $build_os in
- msdosdjgpp*)
- # On DJGPP, this test can blow up pretty badly due to problems in libc
- # (any single argument exceeding 2000 bytes causes a buffer overrun
- # during glob expansion). Even if it were fixed, the result of this
- # check would be larger than it should be.
- lt_cv_sys_max_cmd_len=12288; # 12K is about right
- ;;
-
- gnu*)
- # Under GNU Hurd, this test is not required because there is
- # no limit to the length of command line arguments.
- # Libtool will interpret -1 as no limit whatsoever
- lt_cv_sys_max_cmd_len=-1;
- ;;
-
- cygwin* | mingw* | cegcc*)
- # On Win9x/ME, this test blows up -- it succeeds, but takes
- # about 5 minutes as the teststring grows exponentially.
- # Worse, since 9x/ME are not pre-emptively multitasking,
- # you end up with a "frozen" computer, even though with patience
- # the test eventually succeeds (with a max line length of 256k).
- # Instead, let's just punt: use the minimum linelength reported by
- # all of the supported platforms: 8192 (on NT/2K/XP).
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- mint*)
- # On MiNT this can take a long time and run out of memory.
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- amigaos*)
- # On AmigaOS with pdksh, this test takes hours, literally.
- # So we just punt and use a minimum line length of 8192.
- lt_cv_sys_max_cmd_len=8192;
- ;;
-
- bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
- # This has been around since 386BSD, at least. Likely further.
- if test -x /sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
- elif test -x /usr/sbin/sysctl; then
- lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
- else
- lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
- fi
- # And add a safety zone
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
- ;;
-
- interix*)
- # We know the value 262144 and hardcode it with a safety zone (like BSD)
- lt_cv_sys_max_cmd_len=196608
- ;;
-
- os2*)
- # The test takes a long time on OS/2.
- lt_cv_sys_max_cmd_len=8192
- ;;
-
- osf*)
- # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
- # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
- # nice to cause kernel panics so lets avoid the loop below.
- # First set a reasonable default.
- lt_cv_sys_max_cmd_len=16384
- #
- if test -x /sbin/sysconfig; then
- case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
- *1*) lt_cv_sys_max_cmd_len=-1 ;;
- esac
- fi
- ;;
- sco3.2v5*)
- lt_cv_sys_max_cmd_len=102400
- ;;
- sysv5* | sco5v6* | sysv4.2uw2*)
- kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
- if test -n "$kargmax"; then
- lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
- else
- lt_cv_sys_max_cmd_len=32768
- fi
- ;;
- *)
- lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
- if test -n "$lt_cv_sys_max_cmd_len" && \
- test undefined != "$lt_cv_sys_max_cmd_len"; then
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
- else
- # Make teststring a little bigger before we do anything with it.
- # a 1K string should be a reasonable start.
- for i in 1 2 3 4 5 6 7 8; do
- teststring=$teststring$teststring
- done
- SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
- # If test is not a shell built-in, we'll probably end up computing a
- # maximum length that is only half of the actual maximum length, but
- # we can't tell.
- while { test X`env echo "$teststring$teststring" 2>/dev/null` \
- = "X$teststring$teststring"; } >/dev/null 2>&1 &&
- test 17 != "$i" # 1/2 MB should be enough
- do
- i=`expr $i + 1`
- teststring=$teststring$teststring
- done
- # Only check the string length outside the loop.
- lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
- teststring=
- # Add a significant safety factor because C++ compilers can tack on
- # massive amounts of additional arguments before passing them to the
- # linker. It appears as though 1/2 is a usable value.
- lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
- fi
- ;;
- esac
-
-fi
-
-if test -n "$lt_cv_sys_max_cmd_len"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
-printf "%s\n" "$lt_cv_sys_max_cmd_len" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
-printf "%s\n" "none" >&6; }
-fi
-max_cmd_len=$lt_cv_sys_max_cmd_len
-
-
-
-
-
-
-: ${CP="cp -f"}
-: ${MV="mv -f"}
-: ${RM="rm -f"}
-
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
- lt_unset=unset
-else
- lt_unset=false
-fi
-
-
-
-
-
-# test EBCDIC or ASCII
-case `echo X|tr X '\101'` in
- A) # ASCII based system
- # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
- lt_SP2NL='tr \040 \012'
- lt_NL2SP='tr \015\012 \040\040'
- ;;
- *) # EBCDIC based system
- lt_SP2NL='tr \100 \n'
- lt_NL2SP='tr \r\n \100\100'
- ;;
-esac
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
-printf %s "checking how to convert $build file names to $host format... " >&6; }
-if test ${lt_cv_to_host_file_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
- ;;
- esac
- ;;
- *-*-cygwin* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
- ;;
- *-*-cygwin* )
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
- * ) # otherwise, assume *nix
- lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
- ;;
- esac
- ;;
- * ) # unhandled hosts (and "normal" native builds)
- lt_cv_to_host_file_cmd=func_convert_file_noop
- ;;
-esac
-
-fi
-
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
-printf "%s\n" "$lt_cv_to_host_file_cmd" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
-printf %s "checking how to convert $build file names to toolchain format... " >&6; }
-if test ${lt_cv_to_tool_file_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- #assume ordinary cross tools, or native build.
-lt_cv_to_tool_file_cmd=func_convert_file_noop
-case $host in
- *-*-mingw* )
- case $build in
- *-*-mingw* ) # actually msys
- lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
- ;;
- esac
- ;;
-esac
-
-fi
-
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
-printf "%s\n" "$lt_cv_to_tool_file_cmd" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
-printf %s "checking for $LD option to reload object files... " >&6; }
-if test ${lt_cv_ld_reload_flag+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_reload_flag='-r'
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
-printf "%s\n" "$lt_cv_ld_reload_flag" >&6; }
-reload_flag=$lt_cv_ld_reload_flag
-case $reload_flag in
-"" | " "*) ;;
-*) reload_flag=" $reload_flag" ;;
-esac
-reload_cmds='$LD$reload_flag -o $output$reload_objs'
-case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- if test yes != "$GCC"; then
- reload_cmds=false
- fi
- ;;
- darwin*)
- if test yes = "$GCC"; then
- reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
- else
- reload_cmds='$LD$reload_flag -o $output$reload_objs'
- fi
- ;;
-esac
-
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
-set dummy ${ac_tool_prefix}objdump; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OBJDUMP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$OBJDUMP"; then
- ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-OBJDUMP=$ac_cv_prog_OBJDUMP
-if test -n "$OBJDUMP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
-printf "%s\n" "$OBJDUMP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OBJDUMP"; then
- ac_ct_OBJDUMP=$OBJDUMP
- # Extract the first word of "objdump", so it can be a program name with args.
-set dummy objdump; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OBJDUMP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_OBJDUMP"; then
- ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_OBJDUMP="objdump"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
-if test -n "$ac_ct_OBJDUMP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
-printf "%s\n" "$ac_ct_OBJDUMP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OBJDUMP" = x; then
- OBJDUMP="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- OBJDUMP=$ac_ct_OBJDUMP
- fi
-else
- OBJDUMP="$ac_cv_prog_OBJDUMP"
-fi
-
-test -z "$OBJDUMP" && OBJDUMP=objdump
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
-printf %s "checking how to recognize dependent libraries... " >&6; }
-if test ${lt_cv_deplibs_check_method+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_file_magic_cmd='$MAGIC_CMD'
-lt_cv_file_magic_test_file=
-lt_cv_deplibs_check_method='unknown'
-# Need to set the preceding variable on all platforms that support
-# interlibrary dependencies.
-# 'none' -- dependencies not supported.
-# 'unknown' -- same as none, but documents that we really don't know.
-# 'pass_all' -- all dependencies passed with no checks.
-# 'test_compile' -- check by making test program.
-# 'file_magic [[regex]]' -- check by looking for files in library path
-# that responds to the $file_magic_cmd with a given extended regex.
-# If you have 'file' or equivalent on your system and you're not sure
-# whether 'pass_all' will *always* work, you probably want this one.
-
-case $host_os in
-aix[4-9]*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-beos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-bsdi[45]*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
- lt_cv_file_magic_cmd='/usr/bin/file -L'
- lt_cv_file_magic_test_file=/shlib/libc.so
- ;;
-
-cygwin*)
- # func_win32_libid is a shell function defined in ltmain.sh
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- ;;
-
-mingw* | pw32*)
- # Base MSYS/MinGW do not provide the 'file' command needed by
- # func_win32_libid shell function, so use a weaker test based on 'objdump',
- # unless we find 'file', for example because we are cross-compiling.
- if ( file / ) >/dev/null 2>&1; then
- lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
- lt_cv_file_magic_cmd='func_win32_libid'
- else
- # Keep this pattern in sync with the one in func_win32_libid.
- lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- fi
- ;;
-
-cegcc*)
- # use the weaker test based on 'objdump'. See mingw*.
- lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
- lt_cv_file_magic_cmd='$OBJDUMP -f'
- ;;
-
-darwin* | rhapsody*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-freebsd* | dragonfly*)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- case $host_cpu in
- i*86 )
- # Not sure whether the presence of OpenBSD here was a mistake.
- # Let's accept both of them until this is cleared up.
- lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
- ;;
- esac
- else
- lt_cv_deplibs_check_method=pass_all
- fi
- ;;
-
-haiku*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-hpux10.20* | hpux11*)
- lt_cv_file_magic_cmd=/usr/bin/file
- case $host_cpu in
- ia64*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
- lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
- ;;
- hppa*64*)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
- lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
- ;;
- *)
- lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
- lt_cv_file_magic_test_file=/usr/lib/libc.sl
- ;;
- esac
- ;;
-
-interix[3-9]*)
- # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $LD in
- *-32|*"-32 ") libmagic=32-bit;;
- *-n32|*"-n32 ") libmagic=N32;;
- *-64|*"-64 ") libmagic=64-bit;;
- *) libmagic=never-match;;
- esac
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
- fi
- ;;
-
-newos6*)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
- lt_cv_file_magic_cmd=/usr/bin/file
- lt_cv_file_magic_test_file=/usr/lib/libnls.so
- ;;
-
-*nto* | *qnx*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-openbsd* | bitrig*)
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
- else
- lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
- fi
- ;;
-
-osf3* | osf4* | osf5*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-rdos*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-solaris*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-
-sysv4 | sysv4.3*)
- case $host_vendor in
- motorola)
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
- lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
- ;;
- ncr)
- lt_cv_deplibs_check_method=pass_all
- ;;
- sequent)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
- ;;
- sni)
- lt_cv_file_magic_cmd='/bin/file'
- lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
- lt_cv_file_magic_test_file=/lib/libc.so
- ;;
- siemens)
- lt_cv_deplibs_check_method=pass_all
- ;;
- pc)
- lt_cv_deplibs_check_method=pass_all
- ;;
- esac
- ;;
-
-tpf*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-os2*)
- lt_cv_deplibs_check_method=pass_all
- ;;
-esac
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
-printf "%s\n" "$lt_cv_deplibs_check_method" >&6; }
-
-file_magic_glob=
-want_nocaseglob=no
-if test "$build" = "$host"; then
- case $host_os in
- mingw* | pw32*)
- if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
- want_nocaseglob=yes
- else
- file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
- fi
- ;;
- esac
-fi
-
-file_magic_cmd=$lt_cv_file_magic_cmd
-deplibs_check_method=$lt_cv_deplibs_check_method
-test -z "$deplibs_check_method" && deplibs_check_method=unknown
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dlltool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DLLTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$DLLTOOL"; then
- ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-DLLTOOL=$ac_cv_prog_DLLTOOL
-if test -n "$DLLTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
-printf "%s\n" "$DLLTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DLLTOOL"; then
- ac_ct_DLLTOOL=$DLLTOOL
- # Extract the first word of "dlltool", so it can be a program name with args.
-set dummy dlltool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DLLTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_DLLTOOL"; then
- ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_DLLTOOL="dlltool"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
-if test -n "$ac_ct_DLLTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
-printf "%s\n" "$ac_ct_DLLTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_DLLTOOL" = x; then
- DLLTOOL="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- DLLTOOL=$ac_ct_DLLTOOL
- fi
-else
- DLLTOOL="$ac_cv_prog_DLLTOOL"
-fi
-
-test -z "$DLLTOOL" && DLLTOOL=dlltool
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
-printf %s "checking how to associate runtime and link libraries... " >&6; }
-if test ${lt_cv_sharedlib_from_linklib_cmd+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_sharedlib_from_linklib_cmd='unknown'
-
-case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
- # two different shell functions defined in ltmain.sh;
- # decide which one to use based on capabilities of $DLLTOOL
- case `$DLLTOOL --help 2>&1` in
- *--identify-strict*)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
- ;;
- *)
- lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
- ;;
- esac
- ;;
-*)
- # fallback: assume linklib IS sharedlib
- lt_cv_sharedlib_from_linklib_cmd=$ECHO
- ;;
-esac
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
-printf "%s\n" "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
-sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
-test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
-
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- for ac_prog in ar
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$AR"; then
- ac_cv_prog_AR="$AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-AR=$ac_cv_prog_AR
-if test -n "$AR"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
-printf "%s\n" "$AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$AR" && break
- done
-fi
-if test -z "$AR"; then
- ac_ct_AR=$AR
- for ac_prog in ar
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_AR+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_AR"; then
- ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_AR="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_AR=$ac_cv_prog_ac_ct_AR
-if test -n "$ac_ct_AR"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
-printf "%s\n" "$ac_ct_AR" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$ac_ct_AR" && break
-done
-
- if test "x$ac_ct_AR" = x; then
- AR="false"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- AR=$ac_ct_AR
- fi
-fi
-
-: ${AR=ar}
-: ${AR_FLAGS=cr}
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
-printf %s "checking for archiver @FILE support... " >&6; }
-if test ${lt_cv_ar_at_file+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ar_at_file=no
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- echo conftest.$ac_objext > conftest.lst
- lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
- (eval $lt_ar_try) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if test 0 -eq "$ac_status"; then
- # Ensure the archiver fails upon bogus file names.
- rm -f conftest.$ac_objext libconftest.a
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
- (eval $lt_ar_try) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- if test 0 -ne "$ac_status"; then
- lt_cv_ar_at_file=@
- fi
- fi
- rm -f conftest.* libconftest.a
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
-printf "%s\n" "$lt_cv_ar_at_file" >&6; }
-
-if test no = "$lt_cv_ar_at_file"; then
- archiver_list_spec=
-else
- archiver_list_spec=$lt_cv_ar_at_file
-fi
-
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
-set dummy ${ac_tool_prefix}strip; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$STRIP"; then
- ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_STRIP="${ac_tool_prefix}strip"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-STRIP=$ac_cv_prog_STRIP
-if test -n "$STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
-printf "%s\n" "$STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_STRIP"; then
- ac_ct_STRIP=$STRIP
- # Extract the first word of "strip", so it can be a program name with args.
-set dummy strip; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_STRIP+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_STRIP"; then
- ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_STRIP="strip"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
-if test -n "$ac_ct_STRIP"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
-printf "%s\n" "$ac_ct_STRIP" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_STRIP" = x; then
- STRIP=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- STRIP=$ac_ct_STRIP
- fi
-else
- STRIP="$ac_cv_prog_STRIP"
-fi
-
-test -z "$STRIP" && STRIP=:
-
-
-
-
-
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
-set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$RANLIB"; then
- ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-RANLIB=$ac_cv_prog_RANLIB
-if test -n "$RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-printf "%s\n" "$RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_RANLIB"; then
- ac_ct_RANLIB=$RANLIB
- # Extract the first word of "ranlib", so it can be a program name with args.
-set dummy ranlib; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_RANLIB+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_RANLIB"; then
- ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_RANLIB="ranlib"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
-if test -n "$ac_ct_RANLIB"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-printf "%s\n" "$ac_ct_RANLIB" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_RANLIB" = x; then
- RANLIB=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- RANLIB=$ac_ct_RANLIB
- fi
-else
- RANLIB="$ac_cv_prog_RANLIB"
-fi
-
-test -z "$RANLIB" && RANLIB=:
-
-
-
-
-
-
-# Determine commands to create old-style static archives.
-old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
-old_postinstall_cmds='chmod 644 $oldlib'
-old_postuninstall_cmds=
-
-if test -n "$RANLIB"; then
- case $host_os in
- bitrig* | openbsd*)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
- ;;
- *)
- old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
- ;;
- esac
- old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
-fi
-
-case $host_os in
- darwin*)
- lock_old_archive_extraction=yes ;;
- *)
- lock_old_archive_extraction=no ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-for ac_prog in gawk mawk nawk awk
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_AWK+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$AWK"; then
- ac_cv_prog_AWK="$AWK" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_AWK="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-printf "%s\n" "$AWK" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$AWK" && break
-done
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-
-# Check for command to grab the raw symbol name followed by C symbol from nm.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
-printf %s "checking command to parse $NM output from $compiler object... " >&6; }
-if test ${lt_cv_sys_global_symbol_pipe+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
-# These are sane defaults that work on at least a few old systems.
-# [They come from Ultrix. What could be older than Ultrix?!! ;)]
-
-# Character class describing NM global symbol codes.
-symcode='[BCDEGRST]'
-
-# Regexp to match symbols that can be accessed directly from C.
-sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
-
-# Define system-specific variables.
-case $host_os in
-aix*)
- symcode='[BCDT]'
- ;;
-cygwin* | mingw* | pw32* | cegcc*)
- symcode='[ABCDGISTW]'
- ;;
-hpux*)
- if test ia64 = "$host_cpu"; then
- symcode='[ABCDEGRST]'
- fi
- ;;
-irix* | nonstopux*)
- symcode='[BCDEGRST]'
- ;;
-osf*)
- symcode='[BCDEGQRST]'
- ;;
-solaris*)
- symcode='[BDRT]'
- ;;
-sco3.2v5*)
- symcode='[DT]'
- ;;
-sysv4.2uw2*)
- symcode='[DT]'
- ;;
-sysv5* | sco5v6* | unixware* | OpenUNIX*)
- symcode='[ABDT]'
- ;;
-sysv4)
- symcode='[DFNSTU]'
- ;;
-esac
-
-# If we're using GNU nm, then use its standard symbol codes.
-case `$NM -V 2>&1` in
-*GNU* | *'with BFD'*)
- symcode='[ABCDGIRSTW]' ;;
-esac
-
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Gets list of data symbols to import.
- lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
- # Adjust the below global symbol transforms to fixup imported variables.
- lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
- lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
- lt_c_name_lib_hook="\
- -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
- -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
-else
- # Disable hooks by default.
- lt_cv_sys_global_symbol_to_import=
- lt_cdecl_hook=
- lt_c_name_hook=
- lt_c_name_lib_hook=
-fi
-
-# Transform an extracted symbol line into a proper C declaration.
-# Some systems (esp. on ia64) link data and code symbols differently,
-# so use this general approach.
-lt_cv_sys_global_symbol_to_cdecl="sed -n"\
-$lt_cdecl_hook\
-" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
-
-# Transform an extracted symbol line into symbol name and symbol address
-lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
-$lt_c_name_hook\
-" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
-
-# Transform an extracted symbol line into symbol name with lib prefix and
-# symbol address.
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
-$lt_c_name_lib_hook\
-" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
-" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
-" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
-
-# Handle CRLF in mingw tool chain
-opt_cr=
-case $build_os in
-mingw*)
- opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
- ;;
-esac
-
-# Try without a prefix underscore, then with it.
-for ac_symprfx in "" "_"; do
-
- # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
- symxfrm="\\1 $ac_symprfx\\2 \\2"
-
- # Write the raw and C identifiers.
- if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- # Fake it for dumpbin and say T for any non-static function,
- # D for any global variable and I for any imported variable.
- # Also find C++ and __fastcall symbols from MSVC++,
- # which start with @ or ?.
- lt_cv_sys_global_symbol_pipe="$AWK '"\
-" {last_section=section; section=\$ 3};"\
-" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
-" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
-" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
-" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
-" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
-" \$ 0!~/External *\|/{next};"\
-" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
-" {if(hide[section]) next};"\
-" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
-" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
-" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
-" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
-" ' prfx=^$ac_symprfx"
- else
- lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
- fi
- lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
-
- # Check to see that the pipe works correctly.
- pipe_works=no
-
- rm -f conftest*
- cat > conftest.$ac_ext <<_LT_EOF
-#ifdef __cplusplus
-extern "C" {
-#endif
-char nm_test_var;
-void nm_test_func(void);
-void nm_test_func(void){}
-#ifdef __cplusplus
-}
-#endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
-_LT_EOF
-
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- # Now try to grab the symbols.
- nlist=conftest.nm
- $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5
- if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then
- # Try sorting and uniquifying the output.
- if sort "$nlist" | uniq > "$nlist"T; then
- mv -f "$nlist"T "$nlist"
- else
- rm -f "$nlist"T
- fi
-
- # Make sure that we snagged all the symbols we need.
- if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
- if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
- cat <<_LT_EOF > conftest.$ac_ext
-/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
-#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
-/* DATA imports from DLLs on WIN32 can't be const, because runtime
- relocations are performed -- see ld's documentation on pseudo-relocs. */
-# define LT_DLSYM_CONST
-#elif defined __osf__
-/* This system does not cope well with relocations in const data. */
-# define LT_DLSYM_CONST
-#else
-# define LT_DLSYM_CONST const
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-_LT_EOF
- # Now generate the symbol file.
- eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
-
- cat <<_LT_EOF >> conftest.$ac_ext
-
-/* The mapping between symbol names and symbols. */
-LT_DLSYM_CONST struct {
- const char *name;
- void *address;
-}
-lt__PROGRAM__LTX_preloaded_symbols[] =
-{
- { "@PROGRAM@", (void *) 0 },
-_LT_EOF
- $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
- cat <<\_LT_EOF >> conftest.$ac_ext
- {0, (void *) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt__PROGRAM__LTX_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-_LT_EOF
- # Now try linking the two files.
- mv conftest.$ac_objext conftstm.$ac_objext
- lt_globsym_save_LIBS=$LIBS
- lt_globsym_save_CFLAGS=$CFLAGS
- LIBS=conftstm.$ac_objext
- CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s conftest$ac_exeext; then
- pipe_works=yes
- fi
- LIBS=$lt_globsym_save_LIBS
- CFLAGS=$lt_globsym_save_CFLAGS
- else
- echo "cannot find nm_test_func in $nlist" >&5
- fi
- else
- echo "cannot find nm_test_var in $nlist" >&5
- fi
- else
- echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
- fi
- else
- echo "$progname: failed program was:" >&5
- cat conftest.$ac_ext >&5
- fi
- rm -rf conftest* conftst*
-
- # Do not use the global_symbol_pipe unless it works.
- if test yes = "$pipe_works"; then
- break
- else
- lt_cv_sys_global_symbol_pipe=
- fi
-done
-
-fi
-
-if test -z "$lt_cv_sys_global_symbol_pipe"; then
- lt_cv_sys_global_symbol_to_cdecl=
-fi
-if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-printf "%s\n" "failed" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-printf "%s\n" "ok" >&6; }
-fi
-
-# Response file support.
-if test "$lt_cv_nm_interface" = "MS dumpbin"; then
- nm_file_list_spec='@'
-elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
- nm_file_list_spec='@'
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
-printf %s "checking for sysroot... " >&6; }
-
-# Check whether --with-sysroot was given.
-if test ${with_sysroot+y}
-then :
- withval=$with_sysroot;
-else $as_nop
- with_sysroot=no
-fi
-
-
-lt_sysroot=
-case $with_sysroot in #(
- yes)
- if test yes = "$GCC"; then
- lt_sysroot=`$CC --print-sysroot 2>/dev/null`
- fi
- ;; #(
- /*)
- lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
- ;; #(
- no|'')
- ;; #(
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
-printf "%s\n" "$with_sysroot" >&6; }
- as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
- ;;
-esac
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
-printf "%s\n" "${lt_sysroot:-no}" >&6; }
-
-
-
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
-printf %s "checking for a working dd... " >&6; }
-if test ${ac_cv_path_lt_DD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-: ${lt_DD:=$DD}
-if test -z "$lt_DD"; then
- ac_path_lt_DD_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_prog in dd
- do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_lt_DD="$as_dir$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_lt_DD" || continue
-if "$ac_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then
- cmp -s conftest.i conftest.out \
- && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
-fi
- $ac_path_lt_DD_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_lt_DD"; then
- :
- fi
-else
- ac_cv_path_lt_DD=$lt_DD
-fi
-
-rm -f conftest.i conftest2.i conftest.out
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
-printf "%s\n" "$ac_cv_path_lt_DD" >&6; }
-
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
-printf %s "checking how to truncate binary pipes... " >&6; }
-if test ${lt_cv_truncate_bin+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- printf 0123456789abcdef0123456789abcdef >conftest.i
-cat conftest.i conftest.i >conftest2.i
-lt_cv_truncate_bin=
-if "$ac_cv_path_lt_DD" bs=32 count=1 conftest.out 2>/dev/null; then
- cmp -s conftest.i conftest.out \
- && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
-fi
-rm -f conftest.i conftest2.i conftest.out
-test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
-printf "%s\n" "$lt_cv_truncate_bin" >&6; }
-
-
-
-
-
-
-
-# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
- for cc_temp in $*""; do
- case $cc_temp in
- compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
- distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
- \-*) ;;
- *) break;;
- esac
- done
- func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-
-# Check whether --enable-libtool-lock was given.
-if test ${enable_libtool_lock+y}
-then :
- enableval=$enable_libtool_lock;
-fi
-
-test no = "$enable_libtool_lock" || enable_libtool_lock=yes
-
-# Some flags need to be propagated to the compiler or linker for good
-# libtool support.
-case $host in
-ia64-*-hpux*)
- # Find out what ABI is being produced by ac_compile, and set mode
- # options accordingly.
- echo 'int i;' > conftest.$ac_ext
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.$ac_objext` in
- *ELF-32*)
- HPUX_IA64_MODE=32
- ;;
- *ELF-64*)
- HPUX_IA64_MODE=64
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-*-*-irix6*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo '#line '$LINENO' "configure"' > conftest.$ac_ext
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- if test yes = "$lt_cv_prog_gnu_ld"; then
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -melf32bsmip"
- ;;
- *N32*)
- LD="${LD-ld} -melf32bmipn32"
- ;;
- *64-bit*)
- LD="${LD-ld} -melf64bmip"
- ;;
- esac
- else
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- LD="${LD-ld} -32"
- ;;
- *N32*)
- LD="${LD-ld} -n32"
- ;;
- *64-bit*)
- LD="${LD-ld} -64"
- ;;
- esac
- fi
- fi
- rm -rf conftest*
- ;;
-
-mips64*-*linux*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo '#line '$LINENO' "configure"' > conftest.$ac_ext
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- emul=elf
- case `/usr/bin/file conftest.$ac_objext` in
- *32-bit*)
- emul="${emul}32"
- ;;
- *64-bit*)
- emul="${emul}64"
- ;;
- esac
- case `/usr/bin/file conftest.$ac_objext` in
- *MSB*)
- emul="${emul}btsmip"
- ;;
- *LSB*)
- emul="${emul}ltsmip"
- ;;
- esac
- case `/usr/bin/file conftest.$ac_objext` in
- *N32*)
- emul="${emul}n32"
- ;;
- esac
- LD="${LD-ld} -m $emul"
- fi
- rm -rf conftest*
- ;;
-
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly. Note that the listed cases only cover the
- # situations where additional linker options are needed (such as when
- # doing 32-bit compilation for a host where ld defaults to 64-bit, or
- # vice versa); the common cases where no linker options are needed do
- # not appear in the list.
- echo 'int i;' > conftest.$ac_ext
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
- *32-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_i386_fbsd"
- ;;
- x86_64-*linux*)
- case `/usr/bin/file conftest.o` in
- *x86-64*)
- LD="${LD-ld} -m elf32_x86_64"
- ;;
- *)
- LD="${LD-ld} -m elf_i386"
- ;;
- esac
- ;;
- powerpc64le-*linux*)
- LD="${LD-ld} -m elf32lppclinux"
- ;;
- powerpc64-*linux*)
- LD="${LD-ld} -m elf32ppclinux"
- ;;
- s390x-*linux*)
- LD="${LD-ld} -m elf_s390"
- ;;
- sparc64-*linux*)
- LD="${LD-ld} -m elf32_sparc"
- ;;
- esac
- ;;
- *64-bit*)
- case $host in
- x86_64-*kfreebsd*-gnu)
- LD="${LD-ld} -m elf_x86_64_fbsd"
- ;;
- x86_64-*linux*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- powerpcle-*linux*)
- LD="${LD-ld} -m elf64lppc"
- ;;
- powerpc-*linux*)
- LD="${LD-ld} -m elf64ppc"
- ;;
- s390*-*linux*|s390*-*tpf*)
- LD="${LD-ld} -m elf64_s390"
- ;;
- sparc*-*linux*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-
-*-*-sco3.2v5*)
- # On SCO OpenServer 5, we need -belf to get full-featured binaries.
- SAVE_CFLAGS=$CFLAGS
- CFLAGS="$CFLAGS -belf"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
-printf %s "checking whether the C compiler needs -belf... " >&6; }
-if test ${lt_cv_cc_needs_belf+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_cc_needs_belf=yes
-else $as_nop
- lt_cv_cc_needs_belf=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
-printf "%s\n" "$lt_cv_cc_needs_belf" >&6; }
- if test yes != "$lt_cv_cc_needs_belf"; then
- # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
- CFLAGS=$SAVE_CFLAGS
- fi
- ;;
-*-*solaris*)
- # Find out what ABI is being produced by ac_compile, and set linker
- # options accordingly.
- echo 'int i;' > conftest.$ac_ext
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then
- case `/usr/bin/file conftest.o` in
- *64-bit*)
- case $lt_cv_prog_gnu_ld in
- yes*)
- case $host in
- i?86-*-solaris*|x86_64-*-solaris*)
- LD="${LD-ld} -m elf_x86_64"
- ;;
- sparc*-*-solaris*)
- LD="${LD-ld} -m elf64_sparc"
- ;;
- esac
- # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
- if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
- LD=${LD-ld}_sol2
- fi
- ;;
- *)
- if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
- LD="${LD-ld} -64"
- fi
- ;;
- esac
- ;;
- esac
- fi
- rm -rf conftest*
- ;;
-esac
-
-need_locks=$enable_libtool_lock
-
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
-set dummy ${ac_tool_prefix}mt; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_MANIFEST_TOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$MANIFEST_TOOL"; then
- ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
-if test -n "$MANIFEST_TOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
-printf "%s\n" "$MANIFEST_TOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
- ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
- # Extract the first word of "mt", so it can be a program name with args.
-set dummy mt; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_MANIFEST_TOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_MANIFEST_TOOL"; then
- ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
-if test -n "$ac_ct_MANIFEST_TOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
-printf "%s\n" "$ac_ct_MANIFEST_TOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_MANIFEST_TOOL" = x; then
- MANIFEST_TOOL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
- fi
-else
- MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
-fi
-
-test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
-printf %s "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
-if test ${lt_cv_path_mainfest_tool+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_path_mainfest_tool=no
- echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
- $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
- cat conftest.err >&5
- if $GREP 'Manifest Tool' conftest.out > /dev/null; then
- lt_cv_path_mainfest_tool=yes
- fi
- rm -f conftest*
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
-printf "%s\n" "$lt_cv_path_mainfest_tool" >&6; }
-if test yes != "$lt_cv_path_mainfest_tool"; then
- MANIFEST_TOOL=:
-fi
-
-
-
-
-
-
- case $host_os in
- rhapsody* | darwin*)
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_DSYMUTIL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$DSYMUTIL"; then
- ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-DSYMUTIL=$ac_cv_prog_DSYMUTIL
-if test -n "$DSYMUTIL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
-printf "%s\n" "$DSYMUTIL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DSYMUTIL"; then
- ac_ct_DSYMUTIL=$DSYMUTIL
- # Extract the first word of "dsymutil", so it can be a program name with args.
-set dummy dsymutil; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_DSYMUTIL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_DSYMUTIL"; then
- ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
-if test -n "$ac_ct_DSYMUTIL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
-printf "%s\n" "$ac_ct_DSYMUTIL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_DSYMUTIL" = x; then
- DSYMUTIL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- DSYMUTIL=$ac_ct_DSYMUTIL
- fi
-else
- DSYMUTIL="$ac_cv_prog_DSYMUTIL"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
-set dummy ${ac_tool_prefix}nmedit; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_NMEDIT+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$NMEDIT"; then
- ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-NMEDIT=$ac_cv_prog_NMEDIT
-if test -n "$NMEDIT"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
-printf "%s\n" "$NMEDIT" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_NMEDIT"; then
- ac_ct_NMEDIT=$NMEDIT
- # Extract the first word of "nmedit", so it can be a program name with args.
-set dummy nmedit; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_NMEDIT+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_NMEDIT"; then
- ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_NMEDIT="nmedit"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
-if test -n "$ac_ct_NMEDIT"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
-printf "%s\n" "$ac_ct_NMEDIT" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_NMEDIT" = x; then
- NMEDIT=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- NMEDIT=$ac_ct_NMEDIT
- fi
-else
- NMEDIT="$ac_cv_prog_NMEDIT"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
-set dummy ${ac_tool_prefix}lipo; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_LIPO+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$LIPO"; then
- ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-LIPO=$ac_cv_prog_LIPO
-if test -n "$LIPO"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
-printf "%s\n" "$LIPO" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_LIPO"; then
- ac_ct_LIPO=$LIPO
- # Extract the first word of "lipo", so it can be a program name with args.
-set dummy lipo; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_LIPO+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_LIPO"; then
- ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_LIPO="lipo"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
-if test -n "$ac_ct_LIPO"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
-printf "%s\n" "$ac_ct_LIPO" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_LIPO" = x; then
- LIPO=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- LIPO=$ac_ct_LIPO
- fi
-else
- LIPO="$ac_cv_prog_LIPO"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$OTOOL"; then
- ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-OTOOL=$ac_cv_prog_OTOOL
-if test -n "$OTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-printf "%s\n" "$OTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL"; then
- ac_ct_OTOOL=$OTOOL
- # Extract the first word of "otool", so it can be a program name with args.
-set dummy otool; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OTOOL+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_OTOOL"; then
- ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_OTOOL="otool"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
-if test -n "$ac_ct_OTOOL"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
-printf "%s\n" "$ac_ct_OTOOL" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OTOOL" = x; then
- OTOOL=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- OTOOL=$ac_ct_OTOOL
- fi
-else
- OTOOL="$ac_cv_prog_OTOOL"
-fi
-
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool64; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_OTOOL64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$OTOOL64"; then
- ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-OTOOL64=$ac_cv_prog_OTOOL64
-if test -n "$OTOOL64"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
-printf "%s\n" "$OTOOL64" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_OTOOL64"; then
- ac_ct_OTOOL64=$OTOOL64
- # Extract the first word of "otool64", so it can be a program name with args.
-set dummy otool64; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_ac_ct_OTOOL64+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$ac_ct_OTOOL64"; then
- ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_OTOOL64="otool64"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
-if test -n "$ac_ct_OTOOL64"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
-printf "%s\n" "$ac_ct_OTOOL64" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
- if test "x$ac_ct_OTOOL64" = x; then
- OTOOL64=":"
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- OTOOL64=$ac_ct_OTOOL64
- fi
-else
- OTOOL64="$ac_cv_prog_OTOOL64"
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
-printf %s "checking for -single_module linker flag... " >&6; }
-if test ${lt_cv_apple_cc_single_mod+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_apple_cc_single_mod=no
- if test -z "$LT_MULTI_MODULE"; then
- # By default we will add the -single_module flag. You can override
- # by either setting the environment variable LT_MULTI_MODULE
- # non-empty at configure time, or by adding -multi_module to the
- # link flags.
- rm -rf libconftest.dylib*
- echo "int foo(void){return 1;}" > conftest.c
- echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&5
- $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
- -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
- _lt_result=$?
- # If there is a non-empty error log, and "single_module"
- # appears in it, assume the flag caused a linker warning
- if test -s conftest.err && $GREP single_module conftest.err; then
- cat conftest.err >&5
- # Otherwise, if the output was created with a 0 exit code from
- # the compiler, it worked.
- elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
- lt_cv_apple_cc_single_mod=yes
- else
- cat conftest.err >&5
- fi
- rm -rf libconftest.dylib*
- rm -f conftest.*
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
-printf "%s\n" "$lt_cv_apple_cc_single_mod" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
-printf %s "checking for -exported_symbols_list linker flag... " >&6; }
-if test ${lt_cv_ld_exported_symbols_list+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_exported_symbols_list=no
- save_LDFLAGS=$LDFLAGS
- echo "_main" > conftest.sym
- LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_ld_exported_symbols_list=yes
-else $as_nop
- lt_cv_ld_exported_symbols_list=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
-printf "%s\n" "$lt_cv_ld_exported_symbols_list" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
-printf %s "checking for -force_load linker flag... " >&6; }
-if test ${lt_cv_ld_force_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_ld_force_load=no
- cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
- $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
- echo "$AR cr libconftest.a conftest.o" >&5
- $AR cr libconftest.a conftest.o 2>&5
- echo "$RANLIB libconftest.a" >&5
- $RANLIB libconftest.a 2>&5
- cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
- echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
- $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
- _lt_result=$?
- if test -s conftest.err && $GREP force_load conftest.err; then
- cat conftest.err >&5
- elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
- lt_cv_ld_force_load=yes
- else
- cat conftest.err >&5
- fi
- rm -f conftest.err libconftest.a conftest conftest.c
- rm -rf conftest.dSYM
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
-printf "%s\n" "$lt_cv_ld_force_load" >&6; }
- case $host_os in
- rhapsody* | darwin1.[012])
- _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
- darwin1.*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- darwin*) # darwin 5.x on
- # if running on 10.5 or later, the deployment target defaults
- # to the OS version, if on x86, and 10.4, the deployment
- # target defaults to 10.4. Don't you love it?
- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
- 10.0,*86*-darwin8*|10.0,*-darwin[912]*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- 10.[012][,.]*)
- _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
- 10.*|11.*)
- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
- esac
- ;;
- esac
- if test yes = "$lt_cv_apple_cc_single_mod"; then
- _lt_dar_single_mod='$single_module'
- fi
- if test yes = "$lt_cv_ld_exported_symbols_list"; then
- _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
- else
- _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
- fi
- if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
- _lt_dsymutil='~$DSYMUTIL $lib || :'
- else
- _lt_dsymutil=
- fi
- ;;
- esac
-
-# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-# string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-# string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-# "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-# VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
- case x$2 in
- x)
- ;;
- *:)
- eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
- ;;
- x:*)
- eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
- ;;
- *::*)
- eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
- eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
- ;;
- *)
- eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
- ;;
- esac
-}
-
-ac_header= ac_cache=
-for ac_item in $ac_header_c_list
-do
- if test $ac_cache; then
- ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
- if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
- printf "%s\n" "#define $ac_item 1" >> confdefs.h
- fi
- ac_header= ac_cache=
- elif test $ac_header; then
- ac_cache=$ac_item
- else
- ac_header=$ac_item
- fi
-done
-
-
-
-
-
-
-
-
-if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes
-then :
-
-printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
-"
-if test "x$ac_cv_header_dlfcn_h" = xyes
-then :
- printf "%s\n" "#define HAVE_DLFCN_H 1" >>confdefs.h
-
-fi
-
-
-
-
-
-# Set options
-
-
-
- enable_dlopen=no
-
-
- enable_win32_dll=no
-
-
- # Check whether --enable-shared was given.
-if test ${enable_shared+y}
-then :
- enableval=$enable_shared; p=${PACKAGE-default}
- case $enableval in
- yes) enable_shared=yes ;;
- no) enable_shared=no ;;
- *)
- enable_shared=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_shared=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_shared=yes
-fi
-
-
-
-
-
-
-
-
-
- # Check whether --enable-static was given.
-if test ${enable_static+y}
-then :
- enableval=$enable_static; p=${PACKAGE-default}
- case $enableval in
- yes) enable_static=yes ;;
- no) enable_static=no ;;
- *)
- enable_static=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_static=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_static=yes
-fi
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-pic was given.
-if test ${with_pic+y}
-then :
- withval=$with_pic; lt_p=${PACKAGE-default}
- case $withval in
- yes|no) pic_mode=$withval ;;
- *)
- pic_mode=default
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for lt_pkg in $withval; do
- IFS=$lt_save_ifs
- if test "X$lt_pkg" = "X$lt_p"; then
- pic_mode=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- pic_mode=default
-fi
-
-
-
-
-
-
-
-
- # Check whether --enable-fast-install was given.
-if test ${enable_fast_install+y}
-then :
- enableval=$enable_fast_install; p=${PACKAGE-default}
- case $enableval in
- yes) enable_fast_install=yes ;;
- no) enable_fast_install=no ;;
- *)
- enable_fast_install=no
- # Look at the argument we got. We use all the common list separators.
- lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
- for pkg in $enableval; do
- IFS=$lt_save_ifs
- if test "X$pkg" = "X$p"; then
- enable_fast_install=yes
- fi
- done
- IFS=$lt_save_ifs
- ;;
- esac
-else $as_nop
- enable_fast_install=yes
-fi
-
-
-
-
-
-
-
-
- shared_archive_member_spec=
-case $host,$enable_shared in
-power*-*-aix[5-9]*,yes)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
-printf %s "checking which variant of shared library versioning to provide... " >&6; }
-
-# Check whether --with-aix-soname was given.
-if test ${with_aix_soname+y}
-then :
- withval=$with_aix_soname; case $withval in
- aix|svr4|both)
- ;;
- *)
- as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
- ;;
- esac
- lt_cv_with_aix_soname=$with_aix_soname
-else $as_nop
- if test ${lt_cv_with_aix_soname+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_with_aix_soname=aix
-fi
-
- with_aix_soname=$lt_cv_with_aix_soname
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
-printf "%s\n" "$with_aix_soname" >&6; }
- if test aix != "$with_aix_soname"; then
- # For the AIX way of multilib, we name the shared archive member
- # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
- # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
- # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
- # the AIX toolchain works better with OBJECT_MODE set (default 32).
- if test 64 = "${OBJECT_MODE-32}"; then
- shared_archive_member_spec=shr_64
- else
- shared_archive_member_spec=shr
- fi
- fi
- ;;
-*)
- with_aix_soname=aix
- ;;
-esac
-
-
-
-
-
-
-
-
-
-
-# This can be used to rebuild libtool when needed
-LIBTOOL_DEPS=$ltmain
-
-# Always use our own libtool.
-LIBTOOL='$(SHELL) $(top_builddir)/libtool'
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-test -z "$LN_S" && LN_S="ln -s"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
-printf %s "checking for objdir... " >&6; }
-if test ${lt_cv_objdir+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- rm -f .libs 2>/dev/null
-mkdir .libs 2>/dev/null
-if test -d .libs; then
- lt_cv_objdir=.libs
-else
- # MS-DOS does not allow filenames that begin with a dot.
- lt_cv_objdir=_libs
-fi
-rmdir .libs 2>/dev/null
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
-printf "%s\n" "$lt_cv_objdir" >&6; }
-objdir=$lt_cv_objdir
-
-
-
-
-
-printf "%s\n" "#define LT_OBJDIR \"$lt_cv_objdir/\"" >>confdefs.h
-
-
-
-
-case $host_os in
-aix3*)
- # AIX sometimes has problems with the GCC collect2 program. For some
- # reason, if we set the COLLECT_NAMES environment variable, the problems
- # vanish in a puff of smoke.
- if test set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
- fi
- ;;
-esac
-
-# Global variables:
-ofile=libtool
-can_build_shared=yes
-
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
-libext=a
-
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-old_CC=$CC
-old_CFLAGS=$CFLAGS
-
-# Set sane defaults for various variables
-test -z "$CC" && CC=cc
-test -z "$LTCC" && LTCC=$CC
-test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
-test -z "$LD" && LD=ld
-test -z "$ac_objext" && ac_objext=o
-
-func_cc_basename $compiler
-cc_basename=$func_cc_basename_result
-
-
-# Only perform the check for file, if the check method requires it
-test -z "$MAGIC_CMD" && MAGIC_CMD=file
-case $deplibs_check_method in
-file_magic*)
- if test "$file_magic_cmd" = '$MAGIC_CMD'; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
-printf %s "checking for ${ac_tool_prefix}file... " >&6; }
-if test ${lt_cv_path_MAGIC_CMD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $MAGIC_CMD in
-[\\/*] | ?:[\\/]*)
- lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
- ;;
-*)
- lt_save_MAGIC_CMD=$MAGIC_CMD
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
- for ac_dir in $ac_dummy; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/${ac_tool_prefix}file"; then
- lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD=$lt_cv_path_MAGIC_CMD
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-printf "%s\n" "$MAGIC_CMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
-
-
-
-if test -z "$lt_cv_path_MAGIC_CMD"; then
- if test -n "$ac_tool_prefix"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for file" >&5
-printf %s "checking for file... " >&6; }
-if test ${lt_cv_path_MAGIC_CMD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- case $MAGIC_CMD in
-[\\/*] | ?:[\\/]*)
- lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
- ;;
-*)
- lt_save_MAGIC_CMD=$MAGIC_CMD
- lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
- ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
- for ac_dir in $ac_dummy; do
- IFS=$lt_save_ifs
- test -z "$ac_dir" && ac_dir=.
- if test -f "$ac_dir/file"; then
- lt_cv_path_MAGIC_CMD=$ac_dir/"file"
- if test -n "$file_magic_test_file"; then
- case $deplibs_check_method in
- "file_magic "*)
- file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
- MAGIC_CMD=$lt_cv_path_MAGIC_CMD
- if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
- $EGREP "$file_magic_regex" > /dev/null; then
- :
- else
- cat <<_LT_EOF 1>&2
-
-*** Warning: the command libtool uses to detect shared libraries,
-*** $file_magic_cmd, produces output that libtool cannot recognize.
-*** The result is that libtool may fail to recognize shared libraries
-*** as such. This will affect the creation of libtool libraries that
-*** depend on shared libraries, but programs linked with such libtool
-*** libraries will work regardless of this problem. Nevertheless, you
-*** may want to report the problem to your system manager and/or to
-*** bug-libtool@gnu.org
-
-_LT_EOF
- fi ;;
- esac
- fi
- break
- fi
- done
- IFS=$lt_save_ifs
- MAGIC_CMD=$lt_save_MAGIC_CMD
- ;;
-esac
-fi
-
-MAGIC_CMD=$lt_cv_path_MAGIC_CMD
-if test -n "$MAGIC_CMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
-printf "%s\n" "$MAGIC_CMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- else
- MAGIC_CMD=:
- fi
-fi
-
- fi
- ;;
-esac
-
-# Use C for the default configuration in the libtool script
-
-lt_save_CC=$CC
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-# Source file extension for C test sources.
-ac_ext=c
-
-# Object file extension for compiled C test sources.
-objext=o
-objext=$objext
-
-# Code to be used in simple compile tests
-lt_simple_compile_test_code="int some_variable = 0;"
-
-# Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
-
-
-
-
-
-
-
-# If no C compiler was specified, use CC.
-LTCC=${LTCC-"$CC"}
-
-# If no C compiler flags were specified, use CFLAGS.
-LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
-
-# Allow CC to be a program name with arguments.
-compiler=$CC
-
-# Save the default compiler, since it gets overwritten when the other
-# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
-compiler_DEFAULT=$CC
-
-# save warnings/boilerplate of simple test code
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_compile_test_code" >conftest.$ac_ext
-eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_compiler_boilerplate=`cat conftest.err`
-$RM conftest*
-
-ac_outfile=conftest.$ac_objext
-echo "$lt_simple_link_test_code" >conftest.$ac_ext
-eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
-_lt_linker_boilerplate=`cat conftest.err`
-$RM -r conftest*
-
-
-if test -n "$compiler"; then
-
-lt_prog_compiler_no_builtin_flag=
-
-if test yes = "$GCC"; then
- case $cc_basename in
- nvcc*)
- lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
- *)
- lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
- esac
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
-printf %s "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
-if test ${lt_cv_prog_compiler_rtti_exceptions+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_rtti_exceptions=no
- ac_outfile=conftest.$ac_objext
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_rtti_exceptions=yes
- fi
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
-printf "%s\n" "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
- lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
-else
- :
-fi
-
-fi
-
-
-
-
-
-
- lt_prog_compiler_wl=
-lt_prog_compiler_pic=
-lt_prog_compiler_static=
-
-
- if test yes = "$GCC"; then
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_static='-static'
-
- case $host_os in
- aix*)
- # All AIX code is PIC.
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- lt_prog_compiler_static='-Bstatic'
- fi
- lt_prog_compiler_pic='-fPIC'
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- lt_prog_compiler_pic='-fPIC'
- ;;
- m68k)
- # FIXME: we need at least 68020 code to build shared libraries, but
- # adding the '-m68020' flag to GCC prevents building anything better,
- # like '-m68040'.
- lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
- ;;
- esac
- ;;
-
- beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
- # PIC is the default for these OSes.
- ;;
-
- mingw* | cygwin* | pw32* | os2* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- # Although the cygwin gcc ignores -fPIC, still need this for old-style
- # (--disable-auto-import) libraries
- lt_prog_compiler_pic='-DDLL_EXPORT'
- case $host_os in
- os2*)
- lt_prog_compiler_static='$wl-static'
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_prog_compiler_pic='-fno-common'
- ;;
-
- haiku*)
- # PIC is the default for Haiku.
- # The "-static" flag exists, but is broken.
- lt_prog_compiler_static=
- ;;
-
- hpux*)
- # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
- # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
- # sets the default TLS model and affects inlining.
- case $host_cpu in
- hppa*64*)
- # +Z the default
- ;;
- *)
- lt_prog_compiler_pic='-fPIC'
- ;;
- esac
- ;;
-
- interix[3-9]*)
- # Interix 3.x gcc -fpic/-fPIC options generate broken code.
- # Instead, we relocate shared libraries at runtime.
- ;;
-
- msdosdjgpp*)
- # Just because we use GCC doesn't mean we suddenly get shared libraries
- # on systems that don't support them.
- lt_prog_compiler_can_build_shared=no
- enable_shared=no
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- lt_prog_compiler_pic='-fPIC -shared'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_prog_compiler_pic=-Kconform_pic
- fi
- ;;
-
- *)
- lt_prog_compiler_pic='-fPIC'
- ;;
- esac
-
- case $cc_basename in
- nvcc*) # Cuda Compiler Driver 2.2
- lt_prog_compiler_wl='-Xlinker '
- if test -n "$lt_prog_compiler_pic"; then
- lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
- fi
- ;;
- esac
- else
- # PORTME Check for flag to pass linker flags through the system compiler.
- case $host_os in
- aix*)
- lt_prog_compiler_wl='-Wl,'
- if test ia64 = "$host_cpu"; then
- # AIX 5 now supports IA64 processor
- lt_prog_compiler_static='-Bstatic'
- else
- lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
- fi
- ;;
-
- darwin* | rhapsody*)
- # PIC is the default on this platform
- # Common symbols not allowed in MH_DYLIB files
- lt_prog_compiler_pic='-fno-common'
- case $cc_basename in
- nagfor*)
- # NAG Fortran compiler
- lt_prog_compiler_wl='-Wl,-Wl,,'
- lt_prog_compiler_pic='-PIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
- esac
- ;;
-
- mingw* | cygwin* | pw32* | os2* | cegcc*)
- # This hack is so that the source file can tell whether it is being
- # built for inclusion in a dll (and should export symbols for example).
- lt_prog_compiler_pic='-DDLL_EXPORT'
- case $host_os in
- os2*)
- lt_prog_compiler_static='$wl-static'
- ;;
- esac
- ;;
-
- hpux9* | hpux10* | hpux11*)
- lt_prog_compiler_wl='-Wl,'
- # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
- # not for PA HP-UX.
- case $host_cpu in
- hppa*64*|ia64*)
- # +Z the default
- ;;
- *)
- lt_prog_compiler_pic='+Z'
- ;;
- esac
- # Is there a better lt_prog_compiler_static that works with the bundled CC?
- lt_prog_compiler_static='$wl-a ${wl}archive'
- ;;
-
- irix5* | irix6* | nonstopux*)
- lt_prog_compiler_wl='-Wl,'
- # PIC (with -KPIC) is the default.
- lt_prog_compiler_static='-non_shared'
- ;;
-
- linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- case $cc_basename in
- # old Intel for x86_64, which still supported -KPIC.
- ecc*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-static'
- ;;
- # flang / f18. f95 an alias for gfortran or flang on Debian
- flang* | f18* | f95*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- # icc used to be incompatible with GCC.
- # ICC 10 doesn't accept -KPIC any more.
- icc* | ifort*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- # Lahey Fortran 8.1.
- lf95*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='--shared'
- lt_prog_compiler_static='--static'
- ;;
- nagfor*)
- # NAG Fortran compiler
- lt_prog_compiler_wl='-Wl,-Wl,,'
- lt_prog_compiler_pic='-PIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
- tcc*)
- # Fabrice Bellard et al's Tiny C Compiler
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
- # Portland Group compilers (*not* the Pentium gcc compiler,
- # which looks to be a dead project)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fpic'
- lt_prog_compiler_static='-Bstatic'
- ;;
- ccc*)
- lt_prog_compiler_wl='-Wl,'
- # All Alpha code is PIC.
- lt_prog_compiler_static='-non_shared'
- ;;
- xl* | bgxl* | bgf* | mpixl*)
- # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-qpic'
- lt_prog_compiler_static='-qstaticlink'
- ;;
- *)
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
- # Sun Fortran 8.3 passes all unrecognized flags to the linker
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl=''
- ;;
- *Sun\ F* | *Sun*Fortran*)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl='-Qoption ld '
- ;;
- *Sun\ C*)
- # Sun C 5.9
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- lt_prog_compiler_wl='-Wl,'
- ;;
- *Intel*\ [CF]*Compiler*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fPIC'
- lt_prog_compiler_static='-static'
- ;;
- *Portland\ Group*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-fpic'
- lt_prog_compiler_static='-Bstatic'
- ;;
- esac
- ;;
- esac
- ;;
-
- newsos6)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- *nto* | *qnx*)
- # QNX uses GNU C++, but need to define -shared option too, otherwise
- # it will coredump.
- lt_prog_compiler_pic='-fPIC -shared'
- ;;
-
- osf3* | osf4* | osf5*)
- lt_prog_compiler_wl='-Wl,'
- # All OSF/1 code is PIC.
- lt_prog_compiler_static='-non_shared'
- ;;
-
- rdos*)
- lt_prog_compiler_static='-non_shared'
- ;;
-
- solaris*)
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- case $cc_basename in
- f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
- lt_prog_compiler_wl='-Qoption ld ';;
- *)
- lt_prog_compiler_wl='-Wl,';;
- esac
- ;;
-
- sunos4*)
- lt_prog_compiler_wl='-Qoption ld '
- lt_prog_compiler_pic='-PIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- sysv4 | sysv4.2uw2* | sysv4.3*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- lt_prog_compiler_pic='-Kconform_pic'
- lt_prog_compiler_static='-Bstatic'
- fi
- ;;
-
- sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_pic='-KPIC'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- unicos*)
- lt_prog_compiler_wl='-Wl,'
- lt_prog_compiler_can_build_shared=no
- ;;
-
- uts4*)
- lt_prog_compiler_pic='-pic'
- lt_prog_compiler_static='-Bstatic'
- ;;
-
- *)
- lt_prog_compiler_can_build_shared=no
- ;;
- esac
- fi
-
-case $host_os in
- # For platforms that do not support PIC, -DPIC is meaningless:
- *djgpp*)
- lt_prog_compiler_pic=
- ;;
- *)
- lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
- ;;
-esac
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
-printf %s "checking for $compiler option to produce PIC... " >&6; }
-if test ${lt_cv_prog_compiler_pic+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
-printf "%s\n" "$lt_cv_prog_compiler_pic" >&6; }
-lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
-
-#
-# Check to make sure the PIC flag actually works.
-#
-if test -n "$lt_prog_compiler_pic"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
-printf %s "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
-if test ${lt_cv_prog_compiler_pic_works+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_pic_works=no
- ac_outfile=conftest.$ac_objext
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
- lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- # The option is referenced via a variable to avoid confusing sed.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>conftest.err)
- ac_status=$?
- cat conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s "$ac_outfile"; then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings other than the usual output.
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_pic_works=yes
- fi
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
-printf "%s\n" "$lt_cv_prog_compiler_pic_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_pic_works"; then
- case $lt_prog_compiler_pic in
- "" | " "*) ;;
- *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
- esac
-else
- lt_prog_compiler_pic=
- lt_prog_compiler_can_build_shared=no
-fi
-
-fi
-
-
-
-
-
-
-
-
-
-
-
-#
-# Check to make sure the static flag actually works.
-#
-wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
-printf %s "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
-if test ${lt_cv_prog_compiler_static_works+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_static_works=no
- save_LDFLAGS=$LDFLAGS
- LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
- echo "$lt_simple_link_test_code" > conftest.$ac_ext
- if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_static_works=yes
- fi
- else
- lt_cv_prog_compiler_static_works=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
-printf "%s\n" "$lt_cv_prog_compiler_static_works" >&6; }
-
-if test yes = "$lt_cv_prog_compiler_static_works"; then
- :
-else
- lt_prog_compiler_static=
-fi
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test ${lt_cv_prog_compiler_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_c_o=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_c_o=yes
- fi
- fi
- chmod u+w . 2>&5
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
-printf %s "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
-if test ${lt_cv_prog_compiler_c_o+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler_c_o=no
- $RM -r conftest 2>/dev/null
- mkdir conftest
- cd conftest
- mkdir out
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- lt_compiler_flag="-o out/conftest2.$ac_objext"
- # Insert the option either (1) after the last *FLAGS variable, or
- # (2) before a word containing "conftest.", or (3) at the end.
- # Note that $ac_compile itself does not contain backslashes and begins
- # with a dollar sign (not a hyphen), so the echo should work correctly.
- lt_compile=`echo "$ac_compile" | $SED \
- -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
- -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
- -e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
- (eval "$lt_compile" 2>out/conftest.err)
- ac_status=$?
- cat out/conftest.err >&5
- echo "$as_me:$LINENO: \$? = $ac_status" >&5
- if (exit $ac_status) && test -s out/conftest2.$ac_objext
- then
- # The compiler can only warn and ignore the option if not recognized
- # So say no if there are warnings
- $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
- $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
- if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
- lt_cv_prog_compiler_c_o=yes
- fi
- fi
- chmod u+w . 2>&5
- $RM conftest*
- # SGI C++ compiler will create directory out/ii_files/ for
- # template instantiation
- test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
- $RM out/* && rmdir out
- cd ..
- $RM -r conftest
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
-printf "%s\n" "$lt_cv_prog_compiler_c_o" >&6; }
-
-
-
-
-hard_links=nottested
-if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
- # do not overwrite the value of need_locks provided by the user
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
-printf %s "checking if we can lock with hard links... " >&6; }
- hard_links=yes
- $RM conftest*
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- touch conftest.a
- ln conftest.a conftest.b 2>&5 || hard_links=no
- ln conftest.a conftest.b 2>/dev/null && hard_links=no
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
-printf "%s\n" "$hard_links" >&6; }
- if test no = "$hard_links"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
-printf "%s\n" "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
- need_locks=warn
- fi
-else
- need_locks=no
-fi
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
-printf %s "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
-
- runpath_var=
- allow_undefined_flag=
- always_export_symbols=no
- archive_cmds=
- archive_expsym_cmds=
- compiler_needs_object=no
- enable_shared_with_static_runtimes=no
- export_dynamic_flag_spec=
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
- hardcode_automatic=no
- hardcode_direct=no
- hardcode_direct_absolute=no
- hardcode_libdir_flag_spec=
- hardcode_libdir_separator=
- hardcode_minus_L=no
- hardcode_shlibpath_var=unsupported
- inherit_rpath=no
- link_all_deplibs=unknown
- module_cmds=
- module_expsym_cmds=
- old_archive_from_new_cmds=
- old_archive_from_expsyms_cmds=
- thread_safe_flag_spec=
- whole_archive_flag_spec=
- # include_expsyms should be a list of space-separated symbols to be *always*
- # included in the symbol list
- include_expsyms=
- # exclude_expsyms can be an extended regexp of symbols to exclude
- # it will be wrapped by ' (' and ')$', so one must not match beginning or
- # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
- # as well as any symbol that contains 'd'.
- exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
- # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
- # platforms (ab)use it in PIC code, but their linkers get confused if
- # the symbol is explicitly referenced. Since portable code cannot
- # rely on this symbol name, it's probably fine to never include it in
- # preloaded symbol tables.
- # Exclude shared library initialization/finalization symbols.
- extract_expsyms_cmds=
-
- case $host_os in
- cygwin* | mingw* | pw32* | cegcc*)
- # FIXME: the MSVC++ port hasn't been tested in a loooong time
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- if test yes != "$GCC"; then
- with_gnu_ld=no
- fi
- ;;
- interix*)
- # we just hope/assume this is gcc and not c89 (= MSVC++)
- with_gnu_ld=yes
- ;;
- openbsd* | bitrig*)
- with_gnu_ld=no
- ;;
- linux* | k*bsd*-gnu | gnu*)
- link_all_deplibs=no
- ;;
- esac
-
- ld_shlibs=yes
-
- # On some targets, GNU ld is compatible enough with the native linker
- # that we're better off using the native interface for both.
- lt_use_gnu_ld_interface=no
- if test yes = "$with_gnu_ld"; then
- case $host_os in
- aix*)
- # The AIX port of GNU ld has always aspired to compatibility
- # with the native linker. However, as the warning in the GNU ld
- # block says, versions before 2.19.5* couldn't really create working
- # shared libraries, regardless of the interface used.
- case `$LD -v 2>&1` in
- *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
- *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
- *\ \(GNU\ Binutils\)\ [3-9]*) ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- ;;
- *)
- lt_use_gnu_ld_interface=yes
- ;;
- esac
- fi
-
- if test yes = "$lt_use_gnu_ld_interface"; then
- # If archive_cmds runs LD, not CC, wlarc should be empty
- wlarc='$wl'
-
- # Set some defaults for GNU ld with shared library support. These
- # are reset later if shared libraries are not supported. Putting them
- # here allows them to be overridden if necessary.
- runpath_var=LD_RUN_PATH
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- export_dynamic_flag_spec='$wl--export-dynamic'
- # ancient GNU ld didn't support --whole-archive et. al.
- if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
- whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
- else
- whole_archive_flag_spec=
- fi
- supports_anon_versioning=no
- case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
- *GNU\ gold*) supports_anon_versioning=yes ;;
- *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
- *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
- *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
- *\ 2.11.*) ;; # other 2.11 versions
- *) supports_anon_versioning=yes ;;
- esac
-
- # See if GNU ld supports shared libraries.
- case $host_os in
- aix[3-9]*)
- # On AIX/PPC, the GNU linker is very broken
- if test ia64 != "$host_cpu"; then
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: the GNU linker, at least up to release 2.19, is reported
-*** to be unable to reliably create shared libraries on AIX.
-*** Therefore, libtool is disabling shared libraries support. If you
-*** really care for shared libraries, you may want to install binutils
-*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
-*** You will then need to restart the configuration process.
-
-_LT_EOF
- fi
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds=''
- ;;
- m68k)
- archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- ;;
- esac
- ;;
-
- beos*)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- allow_undefined_flag=unsupported
- # Joseph Beckenbach says some releases of gcc
- # support --undefined. This deserves some investigation. FIXME
- archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
- # as there is no search path for DLLs.
- hardcode_libdir_flag_spec='-L$libdir'
- export_dynamic_flag_spec='$wl--export-all-symbols'
- allow_undefined_flag=unsupported
- always_export_symbols=no
- enable_shared_with_static_runtimes=yes
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
- exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
-
- if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- # If the export-symbols file already is a .def file, use it as
- # is; otherwise, prepend EXPORTS...
- archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
- cp $export_symbols $output_objdir/$soname.def;
- else
- echo EXPORTS > $output_objdir/$soname.def;
- cat $export_symbols >> $output_objdir/$soname.def;
- fi~
- $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- haiku*)
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- link_all_deplibs=yes
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- shrext_cmds=.dll
- archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- prefix_cmds="$SED"~
- if test EXPORTS = "`$SED 1q $export_symbols`"; then
- prefix_cmds="$prefix_cmds -e 1d";
- fi~
- prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
- cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
- enable_shared_with_static_runtimes=yes
- ;;
-
- interix[3-9]*)
- hardcode_direct=no
- hardcode_shlibpath_var=no
- hardcode_libdir_flag_spec='$wl-rpath,$libdir'
- export_dynamic_flag_spec='$wl-E'
- # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
- # Instead, shared libraries are loaded at an image base (0x10000000 by
- # default) and relocated if they conflict, which is a slow very memory
- # consuming and fragmenting process. To avoid this, we pick a random,
- # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
- # time. Moving up from 0x10000000 also allows more sbrk(2) space.
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
- ;;
-
- gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
- tmp_diet=no
- if test linux-dietlibc = "$host_os"; then
- case $cc_basename in
- diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
- esac
- fi
- if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
- && test no = "$tmp_diet"
- then
- tmp_addflag=' $pic_flag'
- tmp_sharedflag='-shared'
- case $cc_basename,$host_cpu in
- pgcc*) # Portland Group C compiler
- whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- tmp_addflag=' $pic_flag'
- ;;
- pgf77* | pgf90* | pgf95* | pgfortran*)
- # Portland Group f77 and f90 compilers
- whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- tmp_addflag=' $pic_flag -Mnomain' ;;
- ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
- tmp_addflag=' -i_dynamic' ;;
- efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
- tmp_addflag=' -i_dynamic -nofor_main' ;;
- ifc* | ifort*) # Intel Fortran compiler
- tmp_addflag=' -nofor_main' ;;
- lf95*) # Lahey Fortran 8.1
- whole_archive_flag_spec=
- tmp_sharedflag='--shared' ;;
- nagfor*) # NAGFOR 5.3
- tmp_sharedflag='-Wl,-shared' ;;
- xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
- tmp_sharedflag='-qmkshrobj'
- tmp_addflag= ;;
- nvcc*) # Cuda Compiler Driver 2.2
- whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- compiler_needs_object=yes
- ;;
- esac
- case `$CC -V 2>&1 | sed 5q` in
- *Sun\ C*) # Sun C 5.9
- whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
- compiler_needs_object=yes
- tmp_sharedflag='-G' ;;
- *Sun\ F*) # Sun Fortran 8.3
- tmp_sharedflag='-G' ;;
- esac
- archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
-
- if test yes = "$supports_anon_versioning"; then
- archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
- fi
-
- case $cc_basename in
- tcc*)
- export_dynamic_flag_spec='-rdynamic'
- ;;
- xlf* | bgf* | bgxlf* | mpixlf*)
- # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
- whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
- if test yes = "$supports_anon_versioning"; then
- archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
- cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
- echo "local: *; };" >> $output_objdir/$libname.ver~
- $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
- fi
- ;;
- esac
- else
- ld_shlibs=no
- fi
- ;;
-
- netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
- wlarc=
- else
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- fi
- ;;
-
- solaris*)
- if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: The releases 2.8.* of the GNU linker cannot reliably
-*** create shared libraries on Solaris systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.9.1 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
- case `$LD -v 2>&1` in
- *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
- ld_shlibs=no
- cat <<_LT_EOF 1>&2
-
-*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
-*** reliably create shared libraries on SCO systems. Therefore, libtool
-*** is disabling shared libraries support. We urge you to upgrade GNU
-*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
-*** your PATH or compiler configuration so that the native linker is
-*** used, and then restart.
-
-_LT_EOF
- ;;
- *)
- # For security reasons, it is highly recommended that you always
- # use absolute paths for naming shared libraries, and exclude the
- # DT_RUNPATH tag from executables and libraries. But doing so
- # requires that you compile everything twice, which is a pain.
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
- ;;
-
- sunos4*)
- archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- wlarc=
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- *)
- if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
- else
- ld_shlibs=no
- fi
- ;;
- esac
-
- if test no = "$ld_shlibs"; then
- runpath_var=
- hardcode_libdir_flag_spec=
- export_dynamic_flag_spec=
- whole_archive_flag_spec=
- fi
- else
- # PORTME fill in a description of your system's linker (not GNU ld)
- case $host_os in
- aix3*)
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
- # Note: this linker hardcodes the directories in LIBPATH if there
- # are no directories specified by -L.
- hardcode_minus_L=yes
- if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
- # Neither direct hardcoding nor static linking is supported with a
- # broken collect2.
- hardcode_direct=unsupported
- fi
- ;;
-
- aix[4-9]*)
- if test ia64 = "$host_cpu"; then
- # On IA64, the linker does run time linking by default, so we don't
- # have to do anything special.
- aix_use_runtimelinking=no
- exp_sym_flag='-Bexport'
- no_entry_flag=
- else
- # If we're using GNU nm, then we don't want the "-C" option.
- # -C means demangle to GNU nm, but means don't demangle to AIX nm.
- # Without the "-l" option, or with the "-B" option, AIX nm treats
- # weak defined symbols like other global defined symbols, whereas
- # GNU nm marks them as "W".
- # While the 'weak' keyword is ignored in the Export File, we need
- # it in the Import File for the 'aix-soname' feature, so we have
- # to replace the "-B" option with "-P" for AIX nm.
- if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
- export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
- else
- export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
- fi
- aix_use_runtimelinking=no
-
- # Test if we are trying to use run time linking or normal
- # AIX style linking. If -brtl is somewhere in LDFLAGS, we
- # have runtime linking enabled, and use it for executables.
- # For shared libraries, we enable/disable runtime linking
- # depending on the kind of the shared library created -
- # when "with_aix_soname,aix_use_runtimelinking" is:
- # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
- # "aix,yes" lib.so shared, rtl:yes, for executables
- # lib.a static archive
- # "both,no" lib.so.V(shr.o) shared, rtl:yes
- # lib.a(lib.so.V) shared, rtl:no, for executables
- # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a(lib.so.V) shared, rtl:no
- # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
- # lib.a static archive
- case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
- for ld_flag in $LDFLAGS; do
- if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
- aix_use_runtimelinking=yes
- break
- fi
- done
- if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
- # With aix-soname=svr4, we create the lib.so.V shared archives only,
- # so we don't have lib.a shared libs to link our executables.
- # We have to force runtime linking in this case.
- aix_use_runtimelinking=yes
- LDFLAGS="$LDFLAGS -Wl,-brtl"
- fi
- ;;
- esac
-
- exp_sym_flag='-bexport'
- no_entry_flag='-bnoentry'
- fi
-
- # When large executables or shared objects are built, AIX ld can
- # have problems creating the table of contents. If linking a library
- # or program results in "error TOC overflow" add -mminimal-toc to
- # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
- # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
-
- archive_cmds=''
- hardcode_direct=yes
- hardcode_direct_absolute=yes
- hardcode_libdir_separator=':'
- link_all_deplibs=yes
- file_list_spec='$wl-f,'
- case $with_aix_soname,$aix_use_runtimelinking in
- aix,*) ;; # traditional, no import file
- svr4,* | *,yes) # use import file
- # The Import File defines what to hardcode.
- hardcode_direct=no
- hardcode_direct_absolute=no
- ;;
- esac
-
- if test yes = "$GCC"; then
- case $host_os in aix4.[012]|aix4.[012].*)
- # We only want to do this on AIX 4.2 and lower, the check
- # below for broken collect2 doesn't work under 4.3+
- collect2name=`$CC -print-prog-name=collect2`
- if test -f "$collect2name" &&
- strings "$collect2name" | $GREP resolve_lib_name >/dev/null
- then
- # We have reworked collect2
- :
- else
- # We have old collect2
- hardcode_direct=unsupported
- # It fails to find uninstalled libraries when the uninstalled
- # path is not listed in the libpath. Setting hardcode_minus_L
- # to unsupported forces relinking
- hardcode_minus_L=yes
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_libdir_separator=
- fi
- ;;
- esac
- shared_flag='-shared'
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag="$shared_flag "'$wl-G'
- fi
- # Need to ensure runtime linking is disabled for the traditional
- # shared library, or the linker may eventually find shared libraries
- # /with/ Import File - we do not want to mix them.
- shared_flag_aix='-shared'
- shared_flag_svr4='-shared $wl-G'
- else
- # not using gcc
- if test ia64 = "$host_cpu"; then
- # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
- # chokes on -Wl,-G. The following line is correct:
- shared_flag='-G'
- else
- if test yes = "$aix_use_runtimelinking"; then
- shared_flag='$wl-G'
- else
- shared_flag='$wl-bM:SRE'
- fi
- shared_flag_aix='$wl-bM:SRE'
- shared_flag_svr4='$wl-G'
- fi
- fi
-
- export_dynamic_flag_spec='$wl-bexpall'
- # It seems that -bexpall does not export symbols beginning with
- # underscore (_), so it is better to generate a list of symbols to export.
- always_export_symbols=yes
- if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
- # Warning - without using the other runtime loading flags (-brtl),
- # -berok will link without error, but may produce a broken library.
- allow_undefined_flag='-berok'
- # Determine the default libpath from the value encoded in an
- # empty executable.
- if test set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- if test ${lt_cv_aix_libpath_+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- lt_aix_libpath_sed='
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }'
- lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=/usr/lib:/lib
- fi
-
-fi
-
- aix_libpath=$lt_cv_aix_libpath_
-fi
-
- hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
- archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
- else
- if test ia64 = "$host_cpu"; then
- hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
- allow_undefined_flag="-z nodefs"
- archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
- else
- # Determine the default libpath from the value encoded in an
- # empty executable.
- if test set = "${lt_cv_aix_libpath+set}"; then
- aix_libpath=$lt_cv_aix_libpath
-else
- if test ${lt_cv_aix_libpath_+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-
- lt_aix_libpath_sed='
- /Import File Strings/,/^$/ {
- /^0/ {
- s/^0 *\([^ ]*\) *$/\1/
- p
- }
- }'
- lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- # Check for a 64-bit object if we didn't find anything.
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
- fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- if test -z "$lt_cv_aix_libpath_"; then
- lt_cv_aix_libpath_=/usr/lib:/lib
- fi
-
-fi
-
- aix_libpath=$lt_cv_aix_libpath_
-fi
-
- hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
- # Warning - without using the other run time loading flags,
- # -berok will link without error, but may produce a broken library.
- no_undefined_flag=' $wl-bernotok'
- allow_undefined_flag=' $wl-berok'
- if test yes = "$with_gnu_ld"; then
- # We only use this code for GNU lds that support --whole-archive.
- whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
- else
- # Exported symbols can be pulled into shared objects from archives
- whole_archive_flag_spec='$convenience'
- fi
- archive_cmds_need_lc=yes
- archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
- # -brtl affects multiple linker settings, -berok does not and is overridden later
- compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
- if test svr4 != "$with_aix_soname"; then
- # This is similar to how AIX traditionally builds its shared libraries.
- archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
- fi
- if test aix != "$with_aix_soname"; then
- archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
- else
- # used by -dlpreopen to get the symbols
- archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
- fi
- archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
- fi
- fi
- ;;
-
- amigaos*)
- case $host_cpu in
- powerpc)
- # see comment about AmigaOS4 .so support
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
- archive_expsym_cmds=''
- ;;
- m68k)
- archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- ;;
- esac
- ;;
-
- bsdi[45]*)
- export_dynamic_flag_spec=-rdynamic
- ;;
-
- cygwin* | mingw* | pw32* | cegcc*)
- # When not using gcc, we currently assume that we are using
- # Microsoft Visual C++.
- # hardcode_libdir_flag_spec is actually meaningless, as there is
- # no search path for DLLs.
- case $cc_basename in
- cl*)
- # Native MSVC
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- always_export_symbols=yes
- file_list_spec='@'
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
- archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
- cp "$export_symbols" "$output_objdir/$soname.def";
- echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
- else
- $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
- fi~
- $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
- linknames='
- # The linker will not automatically build a static lib if we build a DLL.
- # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
- enable_shared_with_static_runtimes=yes
- exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
- export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
- # Don't use ranlib
- old_postinstall_cmds='chmod 644 $oldlib'
- postlink_cmds='lt_outputfile="@OUTPUT@"~
- lt_tool_outputfile="@TOOL_OUTPUT@"~
- case $lt_outputfile in
- *.exe|*.EXE) ;;
- *)
- lt_outputfile=$lt_outputfile.exe
- lt_tool_outputfile=$lt_tool_outputfile.exe
- ;;
- esac~
- if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
- $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
- $RM "$lt_outputfile.manifest";
- fi'
- ;;
- *)
- # Assume MSVC wrapper
- hardcode_libdir_flag_spec=' '
- allow_undefined_flag=unsupported
- # Tell ltmain to make .lib files, not .a files.
- libext=lib
- # Tell ltmain to make .dll files, not .so files.
- shrext_cmds=.dll
- # FIXME: Setting linknames here is a bad hack.
- archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
- # The linker will automatically build a .lib file if we build a DLL.
- old_archive_from_new_cmds='true'
- # FIXME: Should let the user specify the lib program.
- old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
- enable_shared_with_static_runtimes=yes
- ;;
- esac
- ;;
-
- darwin* | rhapsody*)
-
-
- archive_cmds_need_lc=no
- hardcode_direct=no
- hardcode_automatic=yes
- hardcode_shlibpath_var=unsupported
- if test yes = "$lt_cv_ld_force_load"; then
- whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
-
- else
- whole_archive_flag_spec=''
- fi
- link_all_deplibs=yes
- allow_undefined_flag=$_lt_dar_allow_undefined
- case $cc_basename in
- ifort*|nagfor*) _lt_dar_can_shared=yes ;;
- *) _lt_dar_can_shared=$GCC ;;
- esac
- if test yes = "$_lt_dar_can_shared"; then
- output_verbose_link_cmd=func_echo_all
- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
- archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
- module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
-
- else
- ld_shlibs=no
- fi
-
- ;;
-
- dgux*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
- # support. Future versions do this automatically, but an explicit c++rt0.o
- # does not break anything, and helps significantly (at the cost of a little
- # extra space).
- freebsd2.2*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- # Unfortunately, older versions of FreeBSD 2 do not have this feature.
- freebsd2.*)
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
- freebsd* | dragonfly*)
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- hpux9*)
- if test yes = "$GCC"; then
- archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- else
- archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
- fi
- hardcode_libdir_flag_spec='$wl+b $wl$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- export_dynamic_flag_spec='$wl-E'
- ;;
-
- hpux10*)
- if test yes,no = "$GCC,$with_gnu_ld"; then
- archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
- fi
- if test no = "$with_gnu_ld"; then
- hardcode_libdir_flag_spec='$wl+b $wl$libdir'
- hardcode_libdir_separator=:
- hardcode_direct=yes
- hardcode_direct_absolute=yes
- export_dynamic_flag_spec='$wl-E'
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- fi
- ;;
-
- hpux11*)
- if test yes,no = "$GCC,$with_gnu_ld"; then
- case $host_cpu in
- hppa*64*)
- archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- ia64*)
- archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
- archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- else
- case $host_cpu in
- hppa*64*)
- archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- ia64*)
- archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- *)
-
- # Older versions of the 11.00 compiler do not understand -b yet
- # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
-printf %s "checking if $CC understands -b... " >&6; }
-if test ${lt_cv_prog_compiler__b+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_prog_compiler__b=no
- save_LDFLAGS=$LDFLAGS
- LDFLAGS="$LDFLAGS -b"
- echo "$lt_simple_link_test_code" > conftest.$ac_ext
- if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
- # The linker can only warn and ignore the option if not recognized
- # So say no if there are warnings
- if test -s conftest.err; then
- # Append any errors to the config.log.
- cat conftest.err 1>&5
- $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
- $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
- if diff conftest.exp conftest.er2 >/dev/null; then
- lt_cv_prog_compiler__b=yes
- fi
- else
- lt_cv_prog_compiler__b=yes
- fi
- fi
- $RM -r conftest*
- LDFLAGS=$save_LDFLAGS
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
-printf "%s\n" "$lt_cv_prog_compiler__b" >&6; }
-
-if test yes = "$lt_cv_prog_compiler__b"; then
- archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
-else
- archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
-fi
-
- ;;
- esac
- fi
- if test no = "$with_gnu_ld"; then
- hardcode_libdir_flag_spec='$wl+b $wl$libdir'
- hardcode_libdir_separator=:
-
- case $host_cpu in
- hppa*64*|ia64*)
- hardcode_direct=no
- hardcode_shlibpath_var=no
- ;;
- *)
- hardcode_direct=yes
- hardcode_direct_absolute=yes
- export_dynamic_flag_spec='$wl-E'
-
- # hardcode_minus_L: Not really in the search PATH,
- # but as the default location of the library.
- hardcode_minus_L=yes
- ;;
- esac
- fi
- ;;
-
- irix5* | irix6* | nonstopux*)
- if test yes = "$GCC"; then
- archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- # Try to use the -exported_symbol ld option, if it does not
- # work, assume that -exports_file does not work either and
- # implicitly export all symbols.
- # This should be the same for all languages, so no per-tag cache variable.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
-printf %s "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
-if test ${lt_cv_irix_exported_symbol+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- save_LDFLAGS=$LDFLAGS
- LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-int foo (void) { return 0; }
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- lt_cv_irix_exported_symbol=yes
-else $as_nop
- lt_cv_irix_exported_symbol=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
-printf "%s\n" "$lt_cv_irix_exported_symbol" >&6; }
- if test yes = "$lt_cv_irix_exported_symbol"; then
- archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
- fi
- link_all_deplibs=no
- else
- archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- hardcode_libdir_separator=:
- inherit_rpath=yes
- link_all_deplibs=yes
- ;;
-
- linux*)
- case $cc_basename in
- tcc*)
- # Fabrice Bellard et al's Tiny C Compiler
- ld_shlibs=yes
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- ;;
- esac
- ;;
-
- netbsd* | netbsdelf*-gnu)
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
- else
- archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- ;;
-
- newsos6)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- hardcode_libdir_separator=:
- hardcode_shlibpath_var=no
- ;;
-
- *nto* | *qnx*)
- ;;
-
- openbsd* | bitrig*)
- if test -f /usr/libexec/ld.so; then
- hardcode_direct=yes
- hardcode_shlibpath_var=no
- hardcode_direct_absolute=yes
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
- hardcode_libdir_flag_spec='$wl-rpath,$libdir'
- export_dynamic_flag_spec='$wl-E'
- else
- archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
- hardcode_libdir_flag_spec='$wl-rpath,$libdir'
- fi
- else
- ld_shlibs=no
- fi
- ;;
-
- os2*)
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_minus_L=yes
- allow_undefined_flag=unsupported
- shrext_cmds=.dll
- archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
- $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
- $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
- $ECHO EXPORTS >> $output_objdir/$libname.def~
- prefix_cmds="$SED"~
- if test EXPORTS = "`$SED 1q $export_symbols`"; then
- prefix_cmds="$prefix_cmds -e 1d";
- fi~
- prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
- cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
- $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
- emximp -o $lib $output_objdir/$libname.def'
- old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
- enable_shared_with_static_runtimes=yes
- ;;
-
- osf3*)
- if test yes = "$GCC"; then
- allow_undefined_flag=' $wl-expect_unresolved $wl\*'
- archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- hardcode_libdir_separator=:
- ;;
-
- osf4* | osf5*) # as osf3* with the addition of -msym flag
- if test yes = "$GCC"; then
- allow_undefined_flag=' $wl-expect_unresolved $wl\*'
- archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
- hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
- else
- allow_undefined_flag=' -expect_unresolved \*'
- archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
- archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
- $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
-
- # Both c and cxx compiler support -rpath directly
- hardcode_libdir_flag_spec='-rpath $libdir'
- fi
- archive_cmds_need_lc='no'
- hardcode_libdir_separator=:
- ;;
-
- solaris*)
- no_undefined_flag=' -z defs'
- if test yes = "$GCC"; then
- wlarc='$wl'
- archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
- else
- case `$CC -V 2>&1` in
- *"Compilers 5.0"*)
- wlarc=''
- archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
- archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
- ;;
- *)
- wlarc='$wl'
- archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
- $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
- ;;
- esac
- fi
- hardcode_libdir_flag_spec='-R$libdir'
- hardcode_shlibpath_var=no
- case $host_os in
- solaris2.[0-5] | solaris2.[0-5].*) ;;
- *)
- # The compiler driver will combine and reorder linker options,
- # but understands '-z linker_flag'. GCC discards it without '$wl',
- # but is careful enough not to reorder.
- # Supported since Solaris 2.6 (maybe 2.5.1?)
- if test yes = "$GCC"; then
- whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
- else
- whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
- fi
- ;;
- esac
- link_all_deplibs=yes
- ;;
-
- sunos4*)
- if test sequent = "$host_vendor"; then
- # Use $CC to link under sequent, because it throws in some extra .o
- # files that make .init and .fini sections work.
- archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
- fi
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_direct=yes
- hardcode_minus_L=yes
- hardcode_shlibpath_var=no
- ;;
-
- sysv4)
- case $host_vendor in
- sni)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=yes # is this really true???
- ;;
- siemens)
- ## LD is ld it makes a PLAMLIB
- ## CC just makes a GrossModule.
- archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
- reload_cmds='$CC -r -o $output$reload_objs'
- hardcode_direct=no
- ;;
- motorola)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_direct=no #Motorola manual says yes, but my tests say they lie
- ;;
- esac
- runpath_var='LD_RUN_PATH'
- hardcode_shlibpath_var=no
- ;;
-
- sysv4.3*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- export_dynamic_flag_spec='-Bexport'
- ;;
-
- sysv4*MP*)
- if test -d /usr/nec; then
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_shlibpath_var=no
- runpath_var=LD_RUN_PATH
- hardcode_runpath_var=yes
- ld_shlibs=yes
- fi
- ;;
-
- sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
- no_undefined_flag='$wl-z,text'
- archive_cmds_need_lc=no
- hardcode_shlibpath_var=no
- runpath_var='LD_RUN_PATH'
-
- if test yes = "$GCC"; then
- archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- ;;
-
- sysv5* | sco3.2v5* | sco5v6*)
- # Note: We CANNOT use -z defs as we might desire, because we do not
- # link with -lc, and that would cause any symbols used from libc to
- # always be unresolved, which means just about no library would
- # ever link correctly. If we're not using GNU ld we use -z text
- # though, which does catch some bad symbols but isn't as heavy-handed
- # as -z defs.
- no_undefined_flag='$wl-z,text'
- allow_undefined_flag='$wl-z,nodefs'
- archive_cmds_need_lc=no
- hardcode_shlibpath_var=no
- hardcode_libdir_flag_spec='$wl-R,$libdir'
- hardcode_libdir_separator=':'
- link_all_deplibs=yes
- export_dynamic_flag_spec='$wl-Bexport'
- runpath_var='LD_RUN_PATH'
-
- if test yes = "$GCC"; then
- archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- else
- archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
- fi
- ;;
-
- uts4*)
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
- hardcode_libdir_flag_spec='-L$libdir'
- hardcode_shlibpath_var=no
- ;;
-
- *)
- ld_shlibs=no
- ;;
- esac
-
- if test sni = "$host_vendor"; then
- case $host in
- sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
- export_dynamic_flag_spec='$wl-Blargedynsym'
- ;;
- esac
- fi
- fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
-printf "%s\n" "$ld_shlibs" >&6; }
-test no = "$ld_shlibs" && can_build_shared=no
-
-with_gnu_ld=$with_gnu_ld
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#
-# Do we need to explicitly link libc?
-#
-case "x$archive_cmds_need_lc" in
-x|xyes)
- # Assume -lc should be added
- archive_cmds_need_lc=yes
-
- if test yes,yes = "$GCC,$enable_shared"; then
- case $archive_cmds in
- *'~'*)
- # FIXME: we may have to deal with multi-command sequences.
- ;;
- '$CC '*)
- # Test whether the compiler implicitly links with -lc since on some
- # systems, -lgcc has to come before -lc. If gcc already passes -lc
- # to ld, don't add -lc before -lgcc.
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
-printf %s "checking whether -lc should be explicitly linked in... " >&6; }
-if test ${lt_cv_archive_cmds_need_lc+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- $RM conftest*
- echo "$lt_simple_compile_test_code" > conftest.$ac_ext
-
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
- (eval $ac_compile) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } 2>conftest.err; then
- soname=conftest
- lib=conftest
- libobjs=conftest.$ac_objext
- deplibs=
- wl=$lt_prog_compiler_wl
- pic_flag=$lt_prog_compiler_pic
- compiler_flags=-v
- linker_flags=-v
- verstring=
- output_objdir=.
- libname=conftest
- lt_save_allow_undefined_flag=$allow_undefined_flag
- allow_undefined_flag=
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
- (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
- then
- lt_cv_archive_cmds_need_lc=no
- else
- lt_cv_archive_cmds_need_lc=yes
- fi
- allow_undefined_flag=$lt_save_allow_undefined_flag
- else
- cat conftest.err 1>&5
- fi
- $RM conftest*
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
-printf "%s\n" "$lt_cv_archive_cmds_need_lc" >&6; }
- archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
- ;;
- esac
- fi
- ;;
-esac
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
-printf %s "checking dynamic linker characteristics... " >&6; }
-
-if test yes = "$GCC"; then
- case $host_os in
- darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
- *) lt_awk_arg='/^libraries:/' ;;
- esac
- case $host_os in
- mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
- *) lt_sed_strip_eq='s|=/|/|g' ;;
- esac
- lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
- case $lt_search_path_spec in
- *\;*)
- # if the path contains ";" then we assume it to be the separator
- # otherwise default to the standard path separator (i.e. ":") - it is
- # assumed that no part of a normal pathname contains ";" but that should
- # okay in the real world where ";" in dirpaths is itself problematic.
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
- ;;
- *)
- lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
- ;;
- esac
- # Ok, now we have the path, separated by spaces, we can step through it
- # and add multilib dir if necessary...
- lt_tmp_lt_search_path_spec=
- lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
- # ...but if some path component already ends with the multilib dir we assume
- # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
- case "$lt_multi_os_dir; $lt_search_path_spec " in
- "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
- lt_multi_os_dir=
- ;;
- esac
- for lt_sys_path in $lt_search_path_spec; do
- if test -d "$lt_sys_path$lt_multi_os_dir"; then
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
- elif test -n "$lt_multi_os_dir"; then
- test -d "$lt_sys_path" && \
- lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
- fi
- done
- lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
-BEGIN {RS = " "; FS = "/|\n";} {
- lt_foo = "";
- lt_count = 0;
- for (lt_i = NF; lt_i > 0; lt_i--) {
- if ($lt_i != "" && $lt_i != ".") {
- if ($lt_i == "..") {
- lt_count++;
- } else {
- if (lt_count == 0) {
- lt_foo = "/" $lt_i lt_foo;
- } else {
- lt_count--;
- }
- }
- }
- }
- if (lt_foo != "") { lt_freq[lt_foo]++; }
- if (lt_freq[lt_foo] == 1) { print lt_foo; }
-}'`
- # AWK program above erroneously prepends '/' to C:/dos/paths
- # for these hosts.
- case $host_os in
- mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
- $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
- esac
- sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
-else
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
-fi
-library_names_spec=
-libname_spec='lib$name'
-soname_spec=
-shrext_cmds=.so
-postinstall_cmds=
-postuninstall_cmds=
-finish_cmds=
-finish_eval=
-shlibpath_var=
-shlibpath_overrides_runpath=unknown
-version_type=none
-dynamic_linker="$host_os ld.so"
-sys_lib_dlsearch_path_spec="/lib /usr/lib"
-need_lib_prefix=unknown
-hardcode_into_libs=no
-
-# when you set need_version to no, make sure it does not cause -set_version
-# flags to be left without arguments
-need_version=unknown
-
-
-
-case $host_os in
-aix3*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
- shlibpath_var=LIBPATH
-
- # AIX 3 has no versioning support, so we append a major version to the name.
- soname_spec='$libname$release$shared_ext$major'
- ;;
-
-aix[4-9]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- hardcode_into_libs=yes
- if test ia64 = "$host_cpu"; then
- # AIX 5 supports IA64
- library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- else
- # With GCC up to 2.95.x, collect2 would create an import file
- # for dependence libraries. The import file would start with
- # the line '#! .'. This would cause the generated library to
- # depend on '.', always an invalid library. This was fixed in
- # development snapshots of GCC prior to 3.0.
- case $host_os in
- aix4 | aix4.[01] | aix4.[01].*)
- if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
- echo ' yes '
- echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
- :
- else
- can_build_shared=no
- fi
- ;;
- esac
- # Using Import Files as archive members, it is possible to support
- # filename-based versioning of shared library archives on AIX. While
- # this would work for both with and without runtime linking, it will
- # prevent static linking of such archives. So we do filename-based
- # shared library versioning with .so extension only, which is used
- # when both runtime linking and shared linking is enabled.
- # Unfortunately, runtime linking may impact performance, so we do
- # not want this to be the default eventually. Also, we use the
- # versioned .so libs for executables only if there is the -brtl
- # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
- # To allow for filename-based versioning support, we need to create
- # libNAME.so.V as an archive file, containing:
- # *) an Import File, referring to the versioned filename of the
- # archive as well as the shared archive member, telling the
- # bitwidth (32 or 64) of that shared object, and providing the
- # list of exported symbols of that shared object, eventually
- # decorated with the 'weak' keyword
- # *) the shared object with the F_LOADONLY flag set, to really avoid
- # it being seen by the linker.
- # At run time we better use the real file rather than another symlink,
- # but for link time we create the symlink libNAME.so -> libNAME.so.V
-
- case $with_aix_soname,$aix_use_runtimelinking in
- # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
- # soname into executable. Probably we can add versioning support to
- # collect2, so additional links can be useful in future.
- aix,yes) # traditional libtool
- dynamic_linker='AIX unversionable lib.so'
- # If using run time linking (on AIX 4.2 or later) use lib.so
- # instead of lib.a to let people know that these are not
- # typical AIX shared libraries.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- ;;
- aix,no) # traditional AIX only
- dynamic_linker='AIX lib.a(lib.so.V)'
- # We preserve .a as extension for shared libraries through AIX4.2
- # and later when we are not doing run time linking.
- library_names_spec='$libname$release.a $libname.a'
- soname_spec='$libname$release$shared_ext$major'
- ;;
- svr4,*) # full svr4 only
- dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
- library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
- # We do not specify a path in Import Files, so LIBPATH fires.
- shlibpath_overrides_runpath=yes
- ;;
- *,yes) # both, prefer svr4
- dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
- library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
- # unpreferred sharedlib libNAME.a needs extra handling
- postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
- postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
- # We do not specify a path in Import Files, so LIBPATH fires.
- shlibpath_overrides_runpath=yes
- ;;
- *,no) # both, prefer aix
- dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
- library_names_spec='$libname$release.a $libname.a'
- soname_spec='$libname$release$shared_ext$major'
- # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
- postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
- postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
- ;;
- esac
- shlibpath_var=LIBPATH
- fi
- ;;
-
-amigaos*)
- case $host_cpu in
- powerpc)
- # Since July 2007 AmigaOS4 officially supports .so libraries.
- # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- ;;
- m68k)
- library_names_spec='$libname.ixlibrary $libname.a'
- # Create ${libname}_ixlibrary.a entries in /sys/libs.
- finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
- ;;
- esac
- ;;
-
-beos*)
- library_names_spec='$libname$shared_ext'
- dynamic_linker="$host_os ld.so"
- shlibpath_var=LIBRARY_PATH
- ;;
-
-bsdi[45]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
- sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
- # the default ld.so.conf also contains /usr/contrib/lib and
- # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
- # libtool to hard-code these into programs
- ;;
-
-cygwin* | mingw* | pw32* | cegcc*)
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
-
- case $GCC,$cc_basename in
- yes,*)
- # gcc
- library_names_spec='$libname.dll.a'
- # DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname~
- chmod a+x \$dldir/$dlname~
- if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
- eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
- fi'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
-
- case $host_os in
- cygwin*)
- # Cygwin DLLs use 'cyg' prefix rather than 'lib'
- soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
-
- sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
- ;;
- mingw* | cegcc*)
- # MinGW DLLs use traditional 'lib' prefix
- soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
- ;;
- pw32*)
- # pw32 DLLs use 'pw' prefix rather than 'lib'
- library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
- ;;
- esac
- dynamic_linker='Win32 ld.exe'
- ;;
-
- *,cl*)
- # Native MSVC
- libname_spec='$name'
- soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
- library_names_spec='$libname.dll.lib'
-
- case $build_os in
- mingw*)
- sys_lib_search_path_spec=
- lt_save_ifs=$IFS
- IFS=';'
- for lt_path in $LIB
- do
- IFS=$lt_save_ifs
- # Let DOS variable expansion print the short 8.3 style file name.
- lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
- sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
- done
- IFS=$lt_save_ifs
- # Convert to MSYS style.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
- ;;
- cygwin*)
- # Convert to unix form, then to dos form, then back to unix form
- # but this time dos style (no spaces!) so that the unix form looks
- # like /cygdrive/c/PROGRA~1:/cygdr...
- sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
- sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
- sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- ;;
- *)
- sys_lib_search_path_spec=$LIB
- if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
- # It is most probably a Windows format PATH.
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
- else
- sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
- fi
- # FIXME: find the short name or the path components, as spaces are
- # common. (e.g. "Program Files" -> "PROGRA~1")
- ;;
- esac
-
- # DLL is installed to $(libdir)/../bin by postinstall_cmds
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- shlibpath_overrides_runpath=yes
- dynamic_linker='Win32 link.exe'
- ;;
-
- *)
- # Assume MSVC wrapper
- library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
- dynamic_linker='Win32 ld.exe'
- ;;
- esac
- # FIXME: first we should search . and the directory the executable is in
- shlibpath_var=PATH
- ;;
-
-darwin* | rhapsody*)
- dynamic_linker="$host_os dyld"
- version_type=darwin
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
- soname_spec='$libname$release$major$shared_ext'
- shlibpath_overrides_runpath=yes
- shlibpath_var=DYLD_LIBRARY_PATH
- shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
-
- sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
- sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
- ;;
-
-dgux*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-freebsd* | dragonfly*)
- # DragonFly does not have aout. When/if they implement a new
- # versioning mechanism, adjust this.
- if test -x /usr/bin/objformat; then
- objformat=`/usr/bin/objformat`
- else
- case $host_os in
- freebsd[23].*) objformat=aout ;;
- *) objformat=elf ;;
- esac
- fi
- version_type=freebsd-$objformat
- case $version_type in
- freebsd-elf*)
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- need_version=no
- need_lib_prefix=no
- ;;
- freebsd-*)
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- need_version=yes
- ;;
- esac
- shlibpath_var=LD_LIBRARY_PATH
- case $host_os in
- freebsd2.*)
- shlibpath_overrides_runpath=yes
- ;;
- freebsd3.[01]* | freebsdelf3.[01]*)
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
- freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
- *) # from 4.6 on, and DragonFly
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
- esac
- ;;
-
-haiku*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- dynamic_linker="$host_os runtime_loader"
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LIBRARY_PATH
- shlibpath_overrides_runpath=no
- sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
- hardcode_into_libs=yes
- ;;
-
-hpux9* | hpux10* | hpux11*)
- # Give a soname corresponding to the major version so that dld.sl refuses to
- # link against other versions.
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- case $host_cpu in
- ia64*)
- shrext_cmds='.so'
- hardcode_into_libs=yes
- dynamic_linker="$host_os dld.so"
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- if test 32 = "$HPUX_IA64_MODE"; then
- sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
- sys_lib_dlsearch_path_spec=/usr/lib/hpux32
- else
- sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
- sys_lib_dlsearch_path_spec=/usr/lib/hpux64
- fi
- ;;
- hppa*64*)
- shrext_cmds='.sl'
- hardcode_into_libs=yes
- dynamic_linker="$host_os dld.sl"
- shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
- shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
- *)
- shrext_cmds='.sl'
- dynamic_linker="$host_os dld.sl"
- shlibpath_var=SHLIB_PATH
- shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- ;;
- esac
- # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
- postinstall_cmds='chmod 555 $lib'
- # or fails outright, so override atomically:
- install_override_mode=555
- ;;
-
-interix[3-9]*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-irix5* | irix6* | nonstopux*)
- case $host_os in
- nonstopux*) version_type=nonstopux ;;
- *)
- if test yes = "$lt_cv_prog_gnu_ld"; then
- version_type=linux # correct to gnu/linux during the next big refactor
- else
- version_type=irix
- fi ;;
- esac
- need_lib_prefix=no
- need_version=no
- soname_spec='$libname$release$shared_ext$major'
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
- case $host_os in
- irix5* | nonstopux*)
- libsuff= shlibsuff=
- ;;
- *)
- case $LD in # libtool.m4 will add one of these switches to LD
- *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
- libsuff= shlibsuff= libmagic=32-bit;;
- *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
- libsuff=32 shlibsuff=N32 libmagic=N32;;
- *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
- libsuff=64 shlibsuff=64 libmagic=64-bit;;
- *) libsuff= shlibsuff= libmagic=never-match;;
- esac
- ;;
- esac
- shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
- sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
- hardcode_into_libs=yes
- ;;
-
-# No shared lib support for Linux oldld, aout, or coff.
-linux*oldld* | linux*aout* | linux*coff*)
- dynamic_linker=no
- ;;
-
-linux*android*)
- version_type=none # Android doesn't support versioned libraries.
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext'
- soname_spec='$libname$release$shared_ext'
- finish_cmds=
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
-
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- dynamic_linker='Android linker'
- # Don't embed -rpath directories since the linker doesn't support them.
- hardcode_libdir_flag_spec='-L$libdir'
- ;;
-
-# This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
-
- # Some binutils ld are patched to set DT_RUNPATH
- if test ${lt_cv_shlibpath_overrides_runpath+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- lt_cv_shlibpath_overrides_runpath=no
- save_LDFLAGS=$LDFLAGS
- save_libdir=$libdir
- eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
- LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null
-then :
- lt_cv_shlibpath_overrides_runpath=yes
-fi
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
- LDFLAGS=$save_LDFLAGS
- libdir=$save_libdir
-
-fi
-
- shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
-
- # This implies no fast_install, which is unacceptable.
- # Some rework will be needed to allow for fast_install
- # before this can be enabled.
- hardcode_into_libs=yes
-
- # Ideally, we could use ldconfig to report *all* directores which are
- # searched for libraries, however this is still not possible. Aside from not
- # being certain /sbin/ldconfig is available, command
- # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
- # even though it is searched at run-time. Try to do the best guess by
- # appending ld.so.conf contents (and includes) to the search path.
- if test -f /etc/ld.so.conf; then
- lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
- sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
- fi
-
- # We used to test for /lib/ld.so.1 and disable shared libraries on
- # powerpc, because MkLinux only supported shared libraries with the
- # GNU dynamic linker. Since this was broken with cross compilers,
- # most powerpc-linux boxes support dynamic linking these days and
- # people can always --disable-shared, the test was removed, and we
- # assume the GNU/Linux dynamic linker is in use.
- dynamic_linker='GNU/Linux ld.so'
- ;;
-
-netbsdelf*-gnu)
- version_type=linux
- need_lib_prefix=no
- need_version=no
- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
- soname_spec='${libname}${release}${shared_ext}$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='NetBSD ld.elf_so'
- ;;
-
-netbsd*)
- version_type=sunos
- need_lib_prefix=no
- need_version=no
- if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- dynamic_linker='NetBSD (a.out) ld.so'
- else
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- dynamic_linker='NetBSD ld.elf_so'
- fi
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- ;;
-
-newsos6)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-*nto* | *qnx*)
- version_type=qnx
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- dynamic_linker='ldqnx.so'
- ;;
-
-openbsd* | bitrig*)
- version_type=sunos
- sys_lib_dlsearch_path_spec=/usr/lib
- need_lib_prefix=no
- if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
- need_version=no
- else
- need_version=yes
- fi
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- ;;
-
-os2*)
- libname_spec='$name'
- version_type=windows
- shrext_cmds=.dll
- need_version=no
- need_lib_prefix=no
- # OS/2 can only load a DLL with a base name of 8 characters or less.
- soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
- v=$($ECHO $release$versuffix | tr -d .-);
- n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
- $ECHO $n$v`$shared_ext'
- library_names_spec='${libname}_dll.$libext'
- dynamic_linker='OS/2 ld.exe'
- shlibpath_var=BEGINLIBPATH
- sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- postinstall_cmds='base_file=`basename \$file`~
- dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
- dldir=$destdir/`dirname \$dlpath`~
- test -d \$dldir || mkdir -p \$dldir~
- $install_prog $dir/$dlname \$dldir/$dlname~
- chmod a+x \$dldir/$dlname~
- if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
- eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
- fi'
- postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
- dlpath=$dir/\$dldll~
- $RM \$dlpath'
- ;;
-
-osf3* | osf4* | osf5*)
- version_type=osf
- need_lib_prefix=no
- need_version=no
- soname_spec='$libname$release$shared_ext$major'
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
- sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
- ;;
-
-rdos*)
- dynamic_linker=no
- ;;
-
-solaris*)
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- # ldd complains unless libraries are executable
- postinstall_cmds='chmod +x $lib'
- ;;
-
-sunos4*)
- version_type=sunos
- library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
- finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- if test yes = "$with_gnu_ld"; then
- need_lib_prefix=no
- fi
- need_version=yes
- ;;
-
-sysv4 | sysv4.3*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- case $host_vendor in
- sni)
- shlibpath_overrides_runpath=no
- need_lib_prefix=no
- runpath_var=LD_RUN_PATH
- ;;
- siemens)
- need_lib_prefix=no
- ;;
- motorola)
- need_lib_prefix=no
- need_version=no
- shlibpath_overrides_runpath=no
- sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
- ;;
- esac
- ;;
-
-sysv4*MP*)
- if test -d /usr/nec; then
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
- soname_spec='$libname$shared_ext.$major'
- shlibpath_var=LD_LIBRARY_PATH
- fi
- ;;
-
-sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
- version_type=sco
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=yes
- hardcode_into_libs=yes
- if test yes = "$with_gnu_ld"; then
- sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
- else
- sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
- case $host_os in
- sco3.2v5*)
- sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
- ;;
- esac
- fi
- sys_lib_dlsearch_path_spec='/usr/lib'
- ;;
-
-tpf*)
- # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
- version_type=linux # correct to gnu/linux during the next big refactor
- need_lib_prefix=no
- need_version=no
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- shlibpath_var=LD_LIBRARY_PATH
- shlibpath_overrides_runpath=no
- hardcode_into_libs=yes
- ;;
-
-uts4*)
- version_type=linux # correct to gnu/linux during the next big refactor
- library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
- soname_spec='$libname$release$shared_ext$major'
- shlibpath_var=LD_LIBRARY_PATH
- ;;
-
-*)
- dynamic_linker=no
- ;;
-esac
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
-printf "%s\n" "$dynamic_linker" >&6; }
-test no = "$dynamic_linker" && can_build_shared=no
-
-variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
-if test yes = "$GCC"; then
- variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
-fi
-
-if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
- sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
-fi
-
-if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
- sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
-fi
-
-# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
-configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
-
-# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
-func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
-
-# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
-configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
-printf %s "checking how to hardcode library paths into programs... " >&6; }
-hardcode_action=
-if test -n "$hardcode_libdir_flag_spec" ||
- test -n "$runpath_var" ||
- test yes = "$hardcode_automatic"; then
-
- # We can hardcode non-existent directories.
- if test no != "$hardcode_direct" &&
- # If the only mechanism to avoid hardcoding is shlibpath_var, we
- # have to relink, otherwise we might link with an installed library
- # when we should be linking with a yet-to-be-installed one
- ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
- test no != "$hardcode_minus_L"; then
- # Linking always hardcodes the temporary library directory.
- hardcode_action=relink
- else
- # We can link without hardcoding, and we can hardcode nonexisting dirs.
- hardcode_action=immediate
- fi
-else
- # We cannot hardcode anything, or else we can only hardcode existing
- # directories.
- hardcode_action=unsupported
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
-printf "%s\n" "$hardcode_action" >&6; }
-
-if test relink = "$hardcode_action" ||
- test yes = "$inherit_rpath"; then
- # Fast installation is not supported
- enable_fast_install=no
-elif test yes = "$shlibpath_overrides_runpath" ||
- test no = "$enable_shared"; then
- # Fast installation is not necessary
- enable_fast_install=needless
-fi
-
-
-
-
-
-
- if test yes != "$enable_dlopen"; then
- enable_dlopen=unknown
- enable_dlopen_self=unknown
- enable_dlopen_self_static=unknown
-else
- lt_cv_dlopen=no
- lt_cv_dlopen_libs=
-
- case $host_os in
- beos*)
- lt_cv_dlopen=load_add_on
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
- ;;
-
- mingw* | pw32* | cegcc*)
- lt_cv_dlopen=LoadLibrary
- lt_cv_dlopen_libs=
- ;;
-
- cygwin*)
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- ;;
-
- darwin*)
- # if libdl is installed we need to link against it
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-printf %s "checking for dlopen in -ldl... " >&6; }
-if test ${ac_cv_lib_dl_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dl_dlopen=yes
-else $as_nop
- ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes
-then :
- lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
-else $as_nop
-
- lt_cv_dlopen=dyld
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=yes
-
-fi
-
- ;;
-
- tpf*)
- # Don't try to run any link tests for TPF. We know it's impossible
- # because TPF is a cross-compiler, and we know how we open DSOs.
- lt_cv_dlopen=dlopen
- lt_cv_dlopen_libs=
- lt_cv_dlopen_self=no
- ;;
-
- *)
- ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
-if test "x$ac_cv_func_shl_load" = xyes
-then :
- lt_cv_dlopen=shl_load
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
-printf %s "checking for shl_load in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_shl_load+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char shl_load ();
-int
-main (void)
-{
-return shl_load ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_shl_load=yes
-else $as_nop
- ac_cv_lib_dld_shl_load=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
-printf "%s\n" "$ac_cv_lib_dld_shl_load" >&6; }
-if test "x$ac_cv_lib_dld_shl_load" = xyes
-then :
- lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
-else $as_nop
- ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
-if test "x$ac_cv_func_dlopen" = xyes
-then :
- lt_cv_dlopen=dlopen
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-printf %s "checking for dlopen in -ldl... " >&6; }
-if test ${ac_cv_lib_dl_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dl_dlopen=yes
-else $as_nop
- ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes
-then :
- lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
-printf %s "checking for dlopen in -lsvld... " >&6; }
-if test ${ac_cv_lib_svld_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsvld $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_svld_dlopen=yes
-else $as_nop
- ac_cv_lib_svld_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
-printf "%s\n" "$ac_cv_lib_svld_dlopen" >&6; }
-if test "x$ac_cv_lib_svld_dlopen" = xyes
-then :
- lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
-else $as_nop
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
-printf %s "checking for dld_link in -ldld... " >&6; }
-if test ${ac_cv_lib_dld_dld_link+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldld $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char dld_link ();
-int
-main (void)
-{
-return dld_link ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_dld_dld_link=yes
-else $as_nop
- ac_cv_lib_dld_dld_link=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
-printf "%s\n" "$ac_cv_lib_dld_dld_link" >&6; }
-if test "x$ac_cv_lib_dld_dld_link" = xyes
-then :
- lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
-
-fi
-
- ;;
- esac
-
- if test no = "$lt_cv_dlopen"; then
- enable_dlopen=no
- else
- enable_dlopen=yes
- fi
-
- case $lt_cv_dlopen in
- dlopen)
- save_CPPFLAGS=$CPPFLAGS
- test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
-
- save_LDFLAGS=$LDFLAGS
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
-
- save_LIBS=$LIBS
- LIBS="$lt_cv_dlopen_libs $LIBS"
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
-printf %s "checking whether a program can dlopen itself... " >&6; }
-if test ${lt_cv_dlopen_self+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test yes = "$cross_compiling"; then :
- lt_cv_dlopen_self=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include
-#endif
-
-#include
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
- correspondingly for the symbols needed. */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}
-_LT_EOF
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
- (./conftest; exit; ) >&5 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
- x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
-printf "%s\n" "$lt_cv_dlopen_self" >&6; }
-
- if test yes = "$lt_cv_dlopen_self"; then
- wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
-printf %s "checking whether a statically linked program can dlopen itself... " >&6; }
-if test ${lt_cv_dlopen_self_static+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test yes = "$cross_compiling"; then :
- lt_cv_dlopen_self_static=cross
-else
- lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
- lt_status=$lt_dlunknown
- cat > conftest.$ac_ext <<_LT_EOF
-#line $LINENO "configure"
-#include "confdefs.h"
-
-#if HAVE_DLFCN_H
-#include
-#endif
-
-#include
-
-#ifdef RTLD_GLOBAL
-# define LT_DLGLOBAL RTLD_GLOBAL
-#else
-# ifdef DL_GLOBAL
-# define LT_DLGLOBAL DL_GLOBAL
-# else
-# define LT_DLGLOBAL 0
-# endif
-#endif
-
-/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
- find out it does not work in some platform. */
-#ifndef LT_DLLAZY_OR_NOW
-# ifdef RTLD_LAZY
-# define LT_DLLAZY_OR_NOW RTLD_LAZY
-# else
-# ifdef DL_LAZY
-# define LT_DLLAZY_OR_NOW DL_LAZY
-# else
-# ifdef RTLD_NOW
-# define LT_DLLAZY_OR_NOW RTLD_NOW
-# else
-# ifdef DL_NOW
-# define LT_DLLAZY_OR_NOW DL_NOW
-# else
-# define LT_DLLAZY_OR_NOW 0
-# endif
-# endif
-# endif
-# endif
-#endif
-
-/* When -fvisibility=hidden is used, assume the code has been annotated
- correspondingly for the symbols needed. */
-#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
-#endif
-
-int fnord () { return 42; }
-int main ()
-{
- void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
- int status = $lt_dlunknown;
-
- if (self)
- {
- if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
- else
- {
- if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
- else puts (dlerror ());
- }
- /* dlclose (self); */
- }
- else
- puts (dlerror ());
-
- return status;
-}
-_LT_EOF
- if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
- (eval $ac_link) 2>&5
- ac_status=$?
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
- (./conftest; exit; ) >&5 2>/dev/null
- lt_status=$?
- case x$lt_status in
- x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
- x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
- esac
- else :
- # compilation failed
- lt_cv_dlopen_self_static=no
- fi
-fi
-rm -fr conftest*
-
-
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
-printf "%s\n" "$lt_cv_dlopen_self_static" >&6; }
- fi
-
- CPPFLAGS=$save_CPPFLAGS
- LDFLAGS=$save_LDFLAGS
- LIBS=$save_LIBS
- ;;
- esac
-
- case $lt_cv_dlopen_self in
- yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
- *) enable_dlopen_self=unknown ;;
- esac
-
- case $lt_cv_dlopen_self_static in
- yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
- *) enable_dlopen_self_static=unknown ;;
- esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-striplib=
-old_striplib=
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
-printf %s "checking whether stripping libraries is possible... " >&6; }
-if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
- test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
- test -z "$striplib" && striplib="$STRIP --strip-unneeded"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
-# FIXME - insert some real tests, host_os isn't really good enough
- case $host_os in
- darwin*)
- if test -n "$STRIP"; then
- striplib="$STRIP -x"
- old_striplib="$STRIP -S"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- fi
- ;;
- *)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
- esac
-fi
-
-
-
-
-
-
-
-
-
-
-
-
- # Report what library types will actually be built
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
-printf %s "checking if libtool supports shared libraries... " >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
-printf "%s\n" "$can_build_shared" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
-printf %s "checking whether to build shared libraries... " >&6; }
- test no = "$can_build_shared" && enable_shared=no
-
- # On AIX, shared libraries and static libraries use the same namespace, and
- # are all built from PIC.
- case $host_os in
- aix3*)
- test yes = "$enable_shared" && enable_static=no
- if test -n "$RANLIB"; then
- archive_cmds="$archive_cmds~\$RANLIB \$lib"
- postinstall_cmds='$RANLIB $lib'
- fi
- ;;
-
- aix[4-9]*)
- if test ia64 != "$host_cpu"; then
- case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
- yes,aix,yes) ;; # shared object as lib.so file only
- yes,svr4,*) ;; # shared object as lib.so archive member only
- yes,*) enable_static=no ;; # shared object in lib.a archive as well
- esac
- fi
- ;;
- esac
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
-printf "%s\n" "$enable_shared" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
-printf %s "checking whether to build static libraries... " >&6; }
- # Make sure either enable_shared or enable_static is yes.
- test yes = "$enable_shared" || enable_static=yes
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
-printf "%s\n" "$enable_static" >&6; }
-
-
-
-
-fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-CC=$lt_save_CC
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ac_config_commands="$ac_config_commands libtool"
-
-
-
-
-# Only expand once:
-
-
-
- # Find a good install program. We prefer a C program (faster),
-# so one script is as good as another. But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# OS/2's system install, which has a completely different semantic
-# ./install, which can be erroneously created by make from ./install.sh.
-# Reject install programs that cannot install multiple files.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-printf %s "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if test ${ac_cv_path_install+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- # Account for fact that we put trailing slashes in our PATH walk.
-case $as_dir in #((
- ./ | /[cC]/* | \
- /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
- ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
- /usr/ucb/* ) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
- if test $ac_prog = install &&
- grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- elif test $ac_prog = install &&
- grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
- # program-specific install script used by HP pwplus--don't use.
- :
- else
- rm -rf conftest.one conftest.two conftest.dir
- echo one > conftest.one
- echo two > conftest.two
- mkdir conftest.dir
- if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
- test -s conftest.one && test -s conftest.two &&
- test -s conftest.dir/conftest.one &&
- test -s conftest.dir/conftest.two
- then
- ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
- break 3
- fi
- fi
- fi
- done
- done
- ;;
-esac
-
- done
-IFS=$as_save_IFS
-
-rm -rf conftest.one conftest.two conftest.dir
-
-fi
- if test ${ac_cv_path_install+y}; then
- INSTALL=$ac_cv_path_install
- else
- # As a last resort, use the slow shell script. Don't cache a
- # value for INSTALL within a source directory, because that will
- # break other packages using the cache if that directory is
- # removed, or if the value is a relative name.
- INSTALL=$ac_install_sh
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-printf "%s\n" "$INSTALL" >&6; }
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-
-#########
-# Enable large file support (if special flags are necessary)
-#
-# Check whether --enable-largefile was given.
-if test ${enable_largefile+y}
-then :
- enableval=$enable_largefile;
-fi
-
-if test "$enable_largefile" != no; then
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
-printf %s "checking for special C compiler options needed for large files... " >&6; }
-if test ${ac_cv_sys_largefile_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_cv_sys_largefile_CC=no
- if test "$GCC" != yes; then
- ac_save_CC=$CC
- while :; do
- # IRIX 6.2 and later do not support large files by default,
- # so use the C compiler's -n32 option if that helps.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
- if ac_fn_c_try_compile "$LINENO"
-then :
- break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- CC="$CC -n32"
- if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_largefile_CC=' -n32'; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam
- break
- done
- CC=$ac_save_CC
- rm -f conftest.$ac_ext
- fi
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
-printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; }
- if test "$ac_cv_sys_largefile_CC" != no; then
- CC=$CC$ac_cv_sys_largefile_CC
- fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
-printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
-if test ${ac_cv_sys_file_offset_bits+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- while :; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_file_offset_bits=no; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _FILE_OFFSET_BITS 64
-#include
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_file_offset_bits=64; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_cv_sys_file_offset_bits=unknown
- break
-done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
-printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; }
-case $ac_cv_sys_file_offset_bits in #(
- no | unknown) ;;
- *)
-printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h
-;;
-esac
-rm -rf conftest*
- if test $ac_cv_sys_file_offset_bits = unknown; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
-printf %s "checking for _LARGE_FILES value needed for large files... " >&6; }
-if test ${ac_cv_sys_large_files+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- while :; do
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_large_files=no; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#define _LARGE_FILES 1
-#include
- /* Check that off_t can represent 2**63 - 1 correctly.
- We can't simply define LARGE_OFF_T to be 9223372036854775807,
- since some C++ compilers masquerading as C compilers
- incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31))
- int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
- && LARGE_OFF_T % 2147483647 == 1)
- ? 1 : -1];
-int
-main (void)
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
- ac_cv_sys_large_files=1; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_cv_sys_large_files=unknown
- break
-done
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
-printf "%s\n" "$ac_cv_sys_large_files" >&6; }
-case $ac_cv_sys_large_files in #(
- no | unknown) ;;
- *)
-printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h
-;;
-esac
-rm -rf conftest*
- fi
-fi
-
-
-#########
-# Check for needed/wanted data types
-ac_fn_c_check_type "$LINENO" "int8_t" "ac_cv_type_int8_t" "$ac_includes_default"
-if test "x$ac_cv_type_int8_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INT8_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "int16_t" "ac_cv_type_int16_t" "$ac_includes_default"
-if test "x$ac_cv_type_int16_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INT16_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "int32_t" "ac_cv_type_int32_t" "$ac_includes_default"
-if test "x$ac_cv_type_int32_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INT32_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "int64_t" "ac_cv_type_int64_t" "$ac_includes_default"
-if test "x$ac_cv_type_int64_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INT64_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default"
-if test "x$ac_cv_type_intptr_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_INTPTR_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uint8_t" "ac_cv_type_uint8_t" "$ac_includes_default"
-if test "x$ac_cv_type_uint8_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINT8_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uint16_t" "ac_cv_type_uint16_t" "$ac_includes_default"
-if test "x$ac_cv_type_uint16_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINT16_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "$ac_includes_default"
-if test "x$ac_cv_type_uint32_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINT32_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "$ac_includes_default"
-if test "x$ac_cv_type_uint64_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINT64_T 1" >>confdefs.h
-
-
-fi
-ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "$ac_includes_default"
-if test "x$ac_cv_type_uintptr_t" = xyes
-then :
-
-printf "%s\n" "#define HAVE_UINTPTR_T 1" >>confdefs.h
-
-
-fi
-
-
-#########
-# Check for needed/wanted headers
-ac_fn_c_check_header_compile "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_types_h" = xyes
-then :
- printf "%s\n" "#define HAVE_SYS_TYPES_H 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdlib_h" = xyes
-then :
- printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default"
-if test "x$ac_cv_header_stdint_h" = xyes
-then :
- printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "inttypes.h" "ac_cv_header_inttypes_h" "$ac_includes_default"
-if test "x$ac_cv_header_inttypes_h" = xyes
-then :
- printf "%s\n" "#define HAVE_INTTYPES_H 1" >>confdefs.h
-
-fi
-ac_fn_c_check_header_compile "$LINENO" "malloc.h" "ac_cv_header_malloc_h" "$ac_includes_default"
-if test "x$ac_cv_header_malloc_h" = xyes
-then :
- printf "%s\n" "#define HAVE_MALLOC_H 1" >>confdefs.h
-
-fi
-
-
-#########
-# Figure out whether or not we have these functions
-#
-ac_fn_c_check_func "$LINENO" "fdatasync" "ac_cv_func_fdatasync"
-if test "x$ac_cv_func_fdatasync" = xyes
-then :
- printf "%s\n" "#define HAVE_FDATASYNC 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "gmtime_r" "ac_cv_func_gmtime_r"
-if test "x$ac_cv_func_gmtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_GMTIME_R 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "isnan" "ac_cv_func_isnan"
-if test "x$ac_cv_func_isnan" = xyes
-then :
- printf "%s\n" "#define HAVE_ISNAN 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "localtime_r" "ac_cv_func_localtime_r"
-if test "x$ac_cv_func_localtime_r" = xyes
-then :
- printf "%s\n" "#define HAVE_LOCALTIME_R 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "localtime_s" "ac_cv_func_localtime_s"
-if test "x$ac_cv_func_localtime_s" = xyes
-then :
- printf "%s\n" "#define HAVE_LOCALTIME_S 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "malloc_usable_size" "ac_cv_func_malloc_usable_size"
-if test "x$ac_cv_func_malloc_usable_size" = xyes
-then :
- printf "%s\n" "#define HAVE_MALLOC_USABLE_SIZE 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "strchrnul" "ac_cv_func_strchrnul"
-if test "x$ac_cv_func_strchrnul" = xyes
-then :
- printf "%s\n" "#define HAVE_STRCHRNUL 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "usleep" "ac_cv_func_usleep"
-if test "x$ac_cv_func_usleep" = xyes
-then :
- printf "%s\n" "#define HAVE_USLEEP 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "utime" "ac_cv_func_utime"
-if test "x$ac_cv_func_utime" = xyes
-then :
- printf "%s\n" "#define HAVE_UTIME 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
-if test "x$ac_cv_func_pread" = xyes
-then :
- printf "%s\n" "#define HAVE_PREAD 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "pread64" "ac_cv_func_pread64"
-if test "x$ac_cv_func_pread64" = xyes
-then :
- printf "%s\n" "#define HAVE_PREAD64 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite"
-if test "x$ac_cv_func_pwrite" = xyes
-then :
- printf "%s\n" "#define HAVE_PWRITE 1" >>confdefs.h
-
-fi
-ac_fn_c_check_func "$LINENO" "pwrite64" "ac_cv_func_pwrite64"
-if test "x$ac_cv_func_pwrite64" = xyes
-then :
- printf "%s\n" "#define HAVE_PWRITE64 1" >>confdefs.h
-
-fi
-
-
-#########
-# By default, we use the amalgamation (this may be changed below...)
-#
-USE_AMALGAMATION=1
-
-#########
-# See whether we can run specific tclsh versions known to work well;
-# if not, then we fall back to plain tclsh.
-# TODO: try other versions before falling back?
-#
-for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_TCLSH_CMD+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$TCLSH_CMD"; then
- ac_cv_prog_TCLSH_CMD="$TCLSH_CMD" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_TCLSH_CMD="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-TCLSH_CMD=$ac_cv_prog_TCLSH_CMD
-if test -n "$TCLSH_CMD"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TCLSH_CMD" >&5
-printf "%s\n" "$TCLSH_CMD" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$TCLSH_CMD" && break
-done
-test -n "$TCLSH_CMD" || TCLSH_CMD="none"
-
-if test "$TCLSH_CMD" = "none"; then
- # If we can't find a local tclsh, then building the amalgamation will fail.
- # We act as though --disable-amalgamation has been used.
- echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
- USE_AMALGAMATION=0
- TCLSH_CMD="tclsh"
-fi
-
-
-
-if test "x${TCLLIBDIR+set}" != "xset" ; then
- TCLLIBDIR='$(libdir)'
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
- if test -d $i ; then
- TCLLIBDIR=$i
- break
- fi
- done
- TCLLIBDIR="${TCLLIBDIR}/sqlite3"
-fi
-
-#########
-# Set up an appropriate program prefix
-#
-if test "$program_prefix" = "NONE"; then
- program_prefix=""
-fi
-
-
-VERSION=`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'`
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Version set to $VERSION" >&5
-printf "%s\n" "$as_me: Version set to $VERSION" >&6;}
-
-RELEASE=`cat $srcdir/VERSION`
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Release set to $RELEASE" >&5
-printf "%s\n" "$as_me: Release set to $RELEASE" >&6;}
-
-
-##########
-# Handle --with-wasi-sdk=DIR
-#
-# This must be early because it changes the toolchain.
-#
-
-# Check whether --with-wasi-sdk was given.
-if test ${with_wasi_sdk+y}
-then :
- withval=$with_wasi_sdk; with_wasisdk=${withval}
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for WASI SDK directory" >&5
-printf %s "checking for WASI SDK directory... " >&6; }
-if test ${ac_cv_c_wasi_sdk+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # First check to see if --with-tcl was specified.
- if test x"${with_wasi_sdk}" != x ; then
- if ! test -d "${with_wasi_sdk}" ; then
- as_fn_error $? "${with_wasi_sdk} directory doesn't exist" "$LINENO" 5
- fi
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL" >&5
-printf "%s\n" "${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL" >&6; }
- use_wasi_sdk=yes
- else
- use_wasi_sdk=no
- fi
-
-fi
-
-if test "${use_wasi_sdk}" = "no" ; then
- HAVE_WASI_SDK=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-else
- HAVE_WASI_SDK=1
-# Changing --host and --target have no effect here except to possibly
-# cause confusion. autoconf has finished processing them by this
-# point.
-#
-# host_alias=wasm32-wasi
-# target=wasm32-wasi
-#
-# Merely changing CC and LD to the wasi-sdk's is enough to get
-# sqlite3.o building in WASM format.
- CC="${with_wasi_sdk}/bin/clang"
- LD="${with_wasi_sdk}/bin/wasm-ld"
- RANLIB="${with_wasi_sdk}/bin/llvm-ranlib"
- cross_compiling=yes
- enable_threadsafe=no
- use_tcl=no
- enable_tcl=no
- # libtool is apparently hard-coded to use gcc for linking DLLs, so
- # we disable the DLL build...
- enable_shared=no
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-
-
-
-#########
-# Locate a compiler for the build machine. This compiler should
-# generate command-line programs that run on the build machine.
-#
-if test x"$cross_compiling" = xno; then
- BUILD_CC=$CC
- BUILD_CFLAGS=$CFLAGS
-else
- if test "${BUILD_CC+set}" != set; then
- for ac_prog in gcc cc cl
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-printf %s "checking for $ac_word... " >&6; }
-if test ${ac_cv_prog_BUILD_CC+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- if test -n "$BUILD_CC"; then
- ac_cv_prog_BUILD_CC="$BUILD_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
- ac_cv_prog_BUILD_CC="$ac_prog"
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-BUILD_CC=$ac_cv_prog_BUILD_CC
-if test -n "$BUILD_CC"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5
-printf "%s\n" "$BUILD_CC" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-
- test -n "$BUILD_CC" && break
-done
-
- fi
- if test "${BUILD_CFLAGS+set}" != set; then
- BUILD_CFLAGS="-g"
- fi
-fi
-
-
-##########
-# Do we want to support multithreaded use of sqlite
-#
-# Check whether --enable-threadsafe was given.
-if test ${enable_threadsafe+y}
-then :
- enableval=$enable_threadsafe;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support threadsafe operation" >&5
-printf %s "checking whether to support threadsafe operation... " >&6; }
-if test "$enable_threadsafe" = "no"; then
- SQLITE_THREADSAFE=0
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-else
- SQLITE_THREADSAFE=1
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-
-
-if test "$SQLITE_THREADSAFE" = "1"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_create" >&5
-printf %s "checking for library containing pthread_create... " >&6; }
-if test ${ac_cv_search_pthread_create+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char pthread_create ();
-int
-main (void)
-{
-return pthread_create ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' pthread
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_pthread_create=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_pthread_create+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_pthread_create+y}
-then :
-
-else $as_nop
- ac_cv_search_pthread_create=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_create" >&5
-printf "%s\n" "$ac_cv_search_pthread_create" >&6; }
-ac_res=$ac_cv_search_pthread_create
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing pthread_mutexattr_init" >&5
-printf %s "checking for library containing pthread_mutexattr_init... " >&6; }
-if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char pthread_mutexattr_init ();
-int
-main (void)
-{
-return pthread_mutexattr_init ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' pthread
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_pthread_mutexattr_init=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_pthread_mutexattr_init+y}
-then :
-
-else $as_nop
- ac_cv_search_pthread_mutexattr_init=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pthread_mutexattr_init" >&5
-printf "%s\n" "$ac_cv_search_pthread_mutexattr_init" >&6; }
-ac_res=$ac_cv_search_pthread_mutexattr_init
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-fi
-
-##########
-# Which crypto library do we use
-#
-
-# Check whether --with-crypto-lib was given.
-if test ${with_crypto_lib+y}
-then :
- withval=$with_crypto_lib; crypto_lib=$withval
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for crypto library to use" >&5
-printf %s "checking for crypto library to use... " >&6; }
-if test "$crypto_lib" = "none"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none" >&5
-printf "%s\n" "none" >&6; }
-else
- if test "$crypto_lib" = "commoncrypto"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_CC"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_CC"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: commoncrypto" >&5
-printf "%s\n" "commoncrypto" >&6; }
- else
- if test "$crypto_lib" = "libtomcrypt"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_LIBTOMCRYPT"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_LIBTOMCRYPT"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libtomcrypt" >&5
-printf "%s\n" "libtomcrypt" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for register_cipher in -ltomcrypt" >&5
-printf %s "checking for register_cipher in -ltomcrypt... " >&6; }
-if test ${ac_cv_lib_tomcrypt_register_cipher+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-ltomcrypt $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char register_cipher ();
-int
-main (void)
-{
-return register_cipher ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_tomcrypt_register_cipher=yes
-else $as_nop
- ac_cv_lib_tomcrypt_register_cipher=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tomcrypt_register_cipher" >&5
-printf "%s\n" "$ac_cv_lib_tomcrypt_register_cipher" >&6; }
-if test "x$ac_cv_lib_tomcrypt_register_cipher" = xyes
-then :
- printf "%s\n" "#define HAVE_LIBTOMCRYPT 1" >>confdefs.h
-
- LIBS="-ltomcrypt $LIBS"
-
-else $as_nop
- as_fn_error $? "Library crypto not found. Install libtomcrypt!\"" "$LINENO" 5
-fi
-
- else
- if test "$crypto_lib" = "nss"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_NSS"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_NSS"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: nss3" >&5
-printf "%s\n" "nss3" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PK11_Decrypt in -lnss3" >&5
-printf %s "checking for PK11_Decrypt in -lnss3... " >&6; }
-if test ${ac_cv_lib_nss3_PK11_Decrypt+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lnss3 $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char PK11_Decrypt ();
-int
-main (void)
-{
-return PK11_Decrypt ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_nss3_PK11_Decrypt=yes
-else $as_nop
- ac_cv_lib_nss3_PK11_Decrypt=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nss3_PK11_Decrypt" >&5
-printf "%s\n" "$ac_cv_lib_nss3_PK11_Decrypt" >&6; }
-if test "x$ac_cv_lib_nss3_PK11_Decrypt" = xyes
-then :
- printf "%s\n" "#define HAVE_LIBNSS3 1" >>confdefs.h
-
- LIBS="-lnss3 $LIBS"
-
-else $as_nop
- as_fn_error $? "Library crypto not found. Install nss!\"" "$LINENO" 5
-fi
-
- else
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_OPENSSL"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_OPENSSL"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: openssl" >&5
-printf "%s\n" "openssl" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for HMAC_Init_ex in -lcrypto" >&5
-printf %s "checking for HMAC_Init_ex in -lcrypto... " >&6; }
-if test ${ac_cv_lib_crypto_HMAC_Init_ex+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcrypto $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char HMAC_Init_ex ();
-int
-main (void)
-{
-return HMAC_Init_ex ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_crypto_HMAC_Init_ex=yes
-else $as_nop
- ac_cv_lib_crypto_HMAC_Init_ex=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_HMAC_Init_ex" >&5
-printf "%s\n" "$ac_cv_lib_crypto_HMAC_Init_ex" >&6; }
-if test "x$ac_cv_lib_crypto_HMAC_Init_ex" = xyes
-then :
- printf "%s\n" "#define HAVE_LIBCRYPTO 1" >>confdefs.h
-
- LIBS="-lcrypto $LIBS"
-
-else $as_nop
- as_fn_error $? "Library crypto not found. Install openssl!\"" "$LINENO" 5
-fi
-
- fi
- fi
- fi
-fi
-
-##########
-# Do we want to allow a connection created in one thread to be used
-# in another thread. This does not work on many Linux systems (ex: RedHat 9)
-# due to bugs in the threading implementations. This is thus off by default.
-#
-# Check whether --enable-cross-thread-connections was given.
-if test ${enable_cross_thread_connections+y}
-then :
- enableval=$enable_cross_thread_connections;
-else $as_nop
- enable_xthreadconnect=no
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to allow connections to be shared across threads" >&5
-printf %s "checking whether to allow connections to be shared across threads... " >&6; }
-if test "$enable_xthreadconnect" = "no"; then
- XTHREADCONNECT=''
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-else
- XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1'
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-
-
-##########
-# Do we want to support release
-#
-# Check whether --enable-releasemode was given.
-if test ${enable_releasemode+y}
-then :
- enableval=$enable_releasemode;
-else $as_nop
- enable_releasemode=no
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support shared library linked as release mode or not" >&5
-printf %s "checking whether to support shared library linked as release mode or not... " >&6; }
-if test "$enable_releasemode" = "no"; then
- ALLOWRELEASE=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-else
- ALLOWRELEASE="-release `cat $srcdir/VERSION`"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-
-
-##########
-# Do we want temporary databases in memory
-#
-# Check whether --enable-tempstore was given.
-if test ${enable_tempstore+y}
-then :
- enableval=$enable_tempstore;
-else $as_nop
- enable_tempstore=no
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use an in-ram database for temporary tables" >&5
-printf %s "checking whether to use an in-ram database for temporary tables... " >&6; }
-case "$enable_tempstore" in
- never )
- TEMP_STORE=0
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: never" >&5
-printf "%s\n" "never" >&6; }
- ;;
- no )
- TEMP_STORE=1
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
- yes )
- TEMP_STORE=2
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- ;;
- always )
- TEMP_STORE=3
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: always" >&5
-printf "%s\n" "always" >&6; }
- ;;
- * )
- TEMP_STORE=1
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- ;;
-esac
-
-
-
-###########
-# Lots of things are different if we are compiling for Windows using
-# the CYGWIN environment. So check for that special case and handle
-# things accordingly.
-#
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if executables have the .exe suffix" >&5
-printf %s "checking if executables have the .exe suffix... " >&6; }
-if test "$config_BUILD_EXEEXT" = ".exe"; then
- CYGWIN=yes
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unknown" >&5
-printf "%s\n" "unknown" >&6; }
-fi
-if test "$CYGWIN" != "yes"; then
-
-case $host_os in
- *cygwin* ) CYGWIN=yes;;
- * ) CYGWIN=no;;
-esac
-
-fi
-if test "$CYGWIN" = "yes"; then
- BUILD_EXEEXT=.exe
-else
- BUILD_EXEEXT=$EXEEXT
-fi
-if test x"$cross_compiling" = xno; then
- TARGET_EXEEXT=$BUILD_EXEEXT
-else
- TARGET_EXEEXT=$config_TARGET_EXEEXT
-fi
-if test "$TARGET_EXEEXT" = ".exe"; then
- SQLITE_OS_UNIX=0
- SQLITE_OS_WIN=1
- CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
-else
- SQLITE_OS_UNIX=1
- SQLITE_OS_WIN=0
- CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
-fi
-
-
-
-
-
-
-##########
-# Figure out all the parameters needed to compile against Tcl.
-#
-# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
-# macros in the in the tcl.m4 file of the standard TCL distribution.
-# Those macros could not be used directly since we have to make some
-# minor changes to accomodate systems that do not have TCL installed.
-#
-# Check whether --enable-tcl was given.
-if test ${enable_tcl+y}
-then :
- enableval=$enable_tcl; use_tcl=$enableval
-else $as_nop
- use_tcl=yes
-fi
-
-if test "${use_tcl}" = "yes" ; then
-
-# Check whether --with-tcl was given.
-if test ${with_tcl+y}
-then :
- withval=$with_tcl; with_tclconfig=${withval}
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Tcl configuration" >&5
-printf %s "checking for Tcl configuration... " >&6; }
- if test ${ac_cv_c_tclconfig+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
-
- # First check to see if --with-tcl was specified.
- if test x"${with_tclconfig}" != x ; then
- if test -f "${with_tclconfig}/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
- else
- as_fn_error $? "${with_tclconfig} directory doesn't contain tclConfig.sh" "$LINENO" 5
- fi
- fi
-
- # Start autosearch by asking tclsh
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # On ubuntu 14.10, $auto_path on tclsh is not quite correct.
- # So try again after applying corrections.
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # Recent versions of Xcode on Macs hid the tclConfig.sh file
- # in a strange place.
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # then check for a private Tcl installation
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ../tcl \
- `ls -dr ../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../tcl[8-9].[0-9]* 2>/dev/null` \
- ../../tcl \
- `ls -dr ../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../../tcl[8-9].[0-9]* 2>/dev/null` \
- ../../../tcl \
- `ls -dr ../../../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ../../../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ../../../tcl[8-9].[0-9]* 2>/dev/null`
- do
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- `ls -d ${libdir} 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i; pwd)`
- break
- fi
- done
- fi
-
- # check in a few other private locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ${srcdir}/../tcl \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9].[0-9]* 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9] 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[8-9].[0-9]* 2>/dev/null`
- do
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
- break
- fi
- done
- fi
-
-fi
-
-
- if test x"${ac_cv_c_tclconfig}" = x ; then
- use_tcl=no
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Can't find Tcl configuration definitions" >&5
-printf "%s\n" "$as_me: WARNING: Can't find Tcl configuration definitions" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&5
-printf "%s\n" "$as_me: WARNING: *** Without Tcl the regression tests cannot be executed ***" >&2;}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&5
-printf "%s\n" "$as_me: WARNING: *** Consider using --with-tcl=... to define location of Tcl ***" >&2;}
- else
- TCL_BIN_DIR=${ac_cv_c_tclconfig}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found $TCL_BIN_DIR/tclConfig.sh" >&5
-printf "%s\n" "found $TCL_BIN_DIR/tclConfig.sh" >&6; }
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for existence of $TCL_BIN_DIR/tclConfig.sh" >&5
-printf %s "checking for existence of $TCL_BIN_DIR/tclConfig.sh... " >&6; }
- if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: loading" >&5
-printf "%s\n" "loading" >&6; }
- . $TCL_BIN_DIR/tclConfig.sh
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: file not found" >&5
-printf "%s\n" "file not found" >&6; }
- fi
-
- #
- # If the TCL_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable TCL_LIB_SPEC will be set to the value
- # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
- # instead of TCL_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- #
-
- if test -f $TCL_BIN_DIR/Makefile ; then
- TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
- TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
- TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
- fi
-
- #
- # eval is required to do the TCL_DBGX substitution
- #
-
- eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
- eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
- eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
-
- eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
- eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
- eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- fi
-fi
-if test "${use_tcl}" = "no" ; then
- HAVE_TCL=""
-else
- HAVE_TCL=1
-fi
-
-
-##########
-# Figure out what C libraries are required to compile programs
-# that use "readline()" library.
-#
-TARGET_READLINE_LIBS=""
-TARGET_READLINE_INC=""
-TARGET_HAVE_READLINE=0
-TARGET_HAVE_EDITLINE=0
-# Check whether --enable-editline was given.
-if test ${enable_editline+y}
-then :
- enableval=$enable_editline; with_editline=$enableval
-else $as_nop
- with_editline=auto
-fi
-
-# Check whether --enable-readline was given.
-if test ${enable_readline+y}
-then :
- enableval=$enable_readline; with_readline=$enableval
-else $as_nop
- with_readline=auto
-fi
-
-
-if test x"$with_editline" != xno; then
- sLIBS=$LIBS
- LIBS=""
- TARGET_HAVE_EDITLINE=1
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing readline" >&5
-printf %s "checking for library containing readline... " >&6; }
-if test ${ac_cv_search_readline+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char readline ();
-int
-main (void)
-{
-return readline ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' edit
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_readline=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_readline+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_readline+y}
-then :
-
-else $as_nop
- ac_cv_search_readline=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_readline" >&5
-printf "%s\n" "$ac_cv_search_readline" >&6; }
-ac_res=$ac_cv_search_readline
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- with_readline=no
-else $as_nop
- TARGET_HAVE_EDITLINE=0
-fi
-
- TARGET_READLINE_LIBS=$LIBS
- LIBS=$sLIBS
-fi
-if test x"$with_readline" != xno; then
- found="yes"
-
-
-# Check whether --with-readline-lib was given.
-if test ${with_readline_lib+y}
-then :
- withval=$with_readline_lib; with_readline_lib=$withval
-else $as_nop
- with_readline_lib="auto"
-fi
-
- if test "x$with_readline_lib" = xauto; then
- save_LIBS="$LIBS"
- LIBS=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
-printf %s "checking for library containing tgetent... " >&6; }
-if test ${ac_cv_search_tgetent+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char tgetent ();
-int
-main (void)
-{
-return tgetent ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' readline ncurses curses termcap
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_tgetent=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_tgetent+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_tgetent+y}
-then :
-
-else $as_nop
- ac_cv_search_tgetent=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
-printf "%s\n" "$ac_cv_search_tgetent" >&6; }
-ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- term_LIBS="$LIBS"
-else $as_nop
- term_LIBS=""
-fi
-
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
-printf %s "checking for readline in -lreadline... " >&6; }
-if test ${ac_cv_lib_readline_readline+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_check_lib_save_LIBS=$LIBS
-LIBS="-lreadline $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char readline ();
-int
-main (void)
-{
-return readline ();
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_lib_readline_readline=yes
-else $as_nop
- ac_cv_lib_readline_readline=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
-printf "%s\n" "$ac_cv_lib_readline_readline" >&6; }
-if test "x$ac_cv_lib_readline_readline" = xyes
-then :
- TARGET_READLINE_LIBS="-lreadline"
-else $as_nop
- found="no"
-fi
-
- TARGET_READLINE_LIBS="$TARGET_READLINE_LIBS $term_LIBS"
- LIBS="$save_LIBS"
- else
- TARGET_READLINE_LIBS="$with_readline_lib"
- fi
-
-
-# Check whether --with-readline-inc was given.
-if test ${with_readline_inc+y}
-then :
- withval=$with_readline_inc; with_readline_inc=$withval
-else $as_nop
- with_readline_inc="auto"
-fi
-
- if test "x$with_readline_inc" = xauto; then
- ac_fn_c_check_header_compile "$LINENO" "readline.h" "ac_cv_header_readline_h" "$ac_includes_default"
-if test "x$ac_cv_header_readline_h" = xyes
-then :
- found="yes"
-else $as_nop
-
- found="no"
- if test "$cross_compiling" != yes; then
- for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
- for subdir in include include/readline; do
- as_ac_File=`printf "%s\n" "ac_cv_file_$dir/$subdir/readline.h" | $as_tr_sh`
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $dir/$subdir/readline.h" >&5
-printf %s "checking for $dir/$subdir/readline.h... " >&6; }
-if eval test \${$as_ac_File+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- test "$cross_compiling" = yes &&
- as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5
-if test -r "$dir/$subdir/readline.h"; then
- eval "$as_ac_File=yes"
-else
- eval "$as_ac_File=no"
-fi
-fi
-eval ac_res=\$$as_ac_File
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
-if eval test \"x\$"$as_ac_File"\" = x"yes"
-then :
- found=yes
-fi
-
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/$subdir"
- break
- fi
- done
- test "$found" = "yes" && break
- done
- fi
-
-fi
-
- else
- TARGET_READLINE_INC="$with_readline_inc"
- fi
-
- if test x"$found" = xno; then
- TARGET_READLINE_LIBS=""
- TARGET_READLINE_INC=""
- TARGET_HAVE_READLINE=0
- else
- TARGET_HAVE_READLINE=1
- fi
-fi
-
-# Check whether --with-linenoise was given.
-if test ${with_linenoise+y}
-then :
- withval=$with_linenoise; with_linenoise=$withval
-else $as_nop
- with_linenoise="no"
-fi
-
-if test "x$with_linenoise" != "xno"; then
- TARGET_HAVE_READLINE=0
- TARGET_HAVE_EDITLINE=0
- TARGET_HAVE_LINENOISE=1
- TARGET_READLINE_INC="-I${with_linenoise}"
- TARGET_READLINE_LIBS="${with_linenoise}/linenoise.c"
- echo "using linenoise source code at ${with_linenoise}"
-else
- TARGET_HAVE_LINENOISE=0
- echo "not using linenoise"
-fi
-
-
-
-
-
-
-
-
-##########
-# Figure out what C libraries are required to compile programs
-# that use "fdatasync()" function.
-#
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5
-printf %s "checking for library containing fdatasync... " >&6; }
-if test ${ac_cv_search_fdatasync+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char fdatasync ();
-int
-main (void)
-{
-return fdatasync ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' rt
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_fdatasync=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_fdatasync+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_fdatasync+y}
-then :
-
-else $as_nop
- ac_cv_search_fdatasync=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_fdatasync" >&5
-printf "%s\n" "$ac_cv_search_fdatasync" >&6; }
-ac_res=$ac_cv_search_fdatasync
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-
-#########
-# check for debug enabled
-# Check whether --enable-debug was given.
-if test ${enable_debug+y}
-then :
- enableval=$enable_debug;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build type" >&5
-printf %s "checking build type... " >&6; }
-if test "${enable_debug}" = "yes" ; then
- TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: debug" >&5
-printf "%s\n" "debug" >&6; }
-else
- TARGET_DEBUG="-DNDEBUG"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: release" >&5
-printf "%s\n" "release" >&6; }
-fi
-
-
-#########
-# See whether we should use the amalgamation to build
-
-# Check whether --enable-amalgamation was given.
-if test ${enable_amalgamation+y}
-then :
- enableval=$enable_amalgamation;
-fi
-
-if test "${enable_amalgamation}" = "no" ; then
- USE_AMALGAMATION=0
-fi
-
-
-#########
-# By default, amalgamation sqlite3.c will have #line directives.
-# This is a build option not shown by ./configure --help
-# To control it, use configure option: amalgamation_line_macros=?
-# where ? is no to suppress #line directives or yes to create them.
-AMALGAMATION_LINE_MACROS=--linemacros=1
-
-
-if test "${amalgamation_line_macros+set}" = set; then :
- enableval=$amalgamation_line_macros;
-fi
-if test "${amalgamation_line_macros}" = "yes" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=1
-fi
-if test "${amalgamation_line_macros}" = "no" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=0
-fi
-
-#########
-# Look for zlib. Only needed by extensions and by the sqlite3.exe shell
-ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
-if test "x$ac_cv_header_zlib_h" = xyes
-then :
- printf "%s\n" "#define HAVE_ZLIB_H 1" >>confdefs.h
-
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing deflate" >&5
-printf %s "checking for library containing deflate... " >&6; }
-if test ${ac_cv_search_deflate+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char deflate ();
-int
-main (void)
-{
-return deflate ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' z
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_deflate=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_deflate+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_deflate+y}
-then :
-
-else $as_nop
- ac_cv_search_deflate=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_deflate" >&5
-printf "%s\n" "$ac_cv_search_deflate" >&6; }
-ac_res=$ac_cv_search_deflate
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
- HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"
-else $as_nop
- HAVE_ZLIB=""
-fi
-
-
-
-#########
-# See whether we should allow loadable extensions
-# Check whether --enable-load-extension was given.
-if test ${enable_load_extension+y}
-then :
- enableval=$enable_load_extension;
-else $as_nop
- enable_load_extension=yes
-fi
-
-if test "${enable_load_extension}" = "yes" ; then
- OPT_FEATURE_FLAGS=""
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
-printf %s "checking for library containing dlopen... " >&6; }
-if test ${ac_cv_search_dlopen+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char dlopen ();
-int
-main (void)
-{
-return dlopen ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' dl
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_dlopen=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_dlopen+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_dlopen+y}
-then :
-
-else $as_nop
- ac_cv_search_dlopen=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5
-printf "%s\n" "$ac_cv_search_dlopen" >&6; }
-ac_res=$ac_cv_search_dlopen
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
- OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-
-##########
-# Do we want to support math functions
-#
-# Check whether --enable-math was given.
-if test ${enable_math+y}
-then :
- enableval=$enable_math;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support math functions" >&5
-printf %s "checking whether to support math functions... " >&6; }
-if test "$enable_math" = "no"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing ceil" >&5
-printf %s "checking for library containing ceil... " >&6; }
-if test ${ac_cv_search_ceil+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char ceil ();
-int
-main (void)
-{
-return ceil ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' m
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_ceil=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_ceil+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_ceil+y}
-then :
-
-else $as_nop
- ac_cv_search_ceil=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_ceil" >&5
-printf "%s\n" "$ac_cv_search_ceil" >&6; }
-ac_res=$ac_cv_search_ceil
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-fi
-
-##########
-# Do we want to support JSON functions
-#
-# Check whether --enable-json was given.
-if test ${enable_json+y}
-then :
- enableval=$enable_json;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support JSON functions" >&5
-printf %s "checking whether to support JSON functions... " >&6; }
-if test "$enable_json" = "no"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-fi
-
-########
-# The --enable-all argument is short-hand to enable
-# multiple extensions.
-# Check whether --enable-all was given.
-if test ${enable_all+y}
-then :
- enableval=$enable_all;
-fi
-
-
-##########
-# Do we want to support memsys3 and/or memsys5
-#
-# Check whether --enable-memsys5 was given.
-if test ${enable_memsys5+y}
-then :
- enableval=$enable_memsys5;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS5" >&5
-printf %s "checking whether to support MEMSYS5... " >&6; }
-if test "${enable_memsys5}" = "yes"; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS5"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-# Check whether --enable-memsys3 was given.
-if test ${enable_memsys3+y}
-then :
- enableval=$enable_memsys3;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support MEMSYS3" >&5
-printf %s "checking whether to support MEMSYS3... " >&6; }
-if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS3"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# See whether we should enable Full Text Search extensions
-# Check whether --enable-fts3 was given.
-if test ${enable_fts3+y}
-then :
- enableval=$enable_fts3;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support FTS3" >&5
-printf %s "checking whether to support FTS3... " >&6; }
-if test "${enable_fts3}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-# Check whether --enable-fts4 was given.
-if test ${enable_fts4+y}
-then :
- enableval=$enable_fts4;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support FTS4" >&5
-printf %s "checking whether to support FTS4... " >&6; }
-if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
-printf %s "checking for library containing log... " >&6; }
-if test ${ac_cv_search_log+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char log ();
-int
-main (void)
-{
-return log ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' m
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_log=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_log+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_log+y}
-then :
-
-else $as_nop
- ac_cv_search_log=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5
-printf "%s\n" "$ac_cv_search_log" >&6; }
-ac_res=$ac_cv_search_log
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-# Check whether --enable-fts5 was given.
-if test ${enable_fts5+y}
-then :
- enableval=$enable_fts5;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support FTS5" >&5
-printf %s "checking whether to support FTS5... " >&6; }
-if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing log" >&5
-printf %s "checking for library containing log... " >&6; }
-if test ${ac_cv_search_log+y}
-then :
- printf %s "(cached) " >&6
-else $as_nop
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-char log ();
-int
-main (void)
-{
-return log ();
- ;
- return 0;
-}
-_ACEOF
-for ac_lib in '' m
-do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"
-then :
- ac_cv_search_log=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
- conftest$ac_exeext
- if test ${ac_cv_search_log+y}
-then :
- break
-fi
-done
-if test ${ac_cv_search_log+y}
-then :
-
-else $as_nop
- ac_cv_search_log=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_log" >&5
-printf "%s\n" "$ac_cv_search_log" >&6; }
-ac_res=$ac_cv_search_log
-if test "$ac_res" != no
-then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-fi
-
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# See whether we should enable the LIMIT clause on UPDATE and DELETE
-# statements.
-# Check whether --enable-update-limit was given.
-if test ${enable_update_limit+y}
-then :
- enableval=$enable_update_limit;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support LIMIT on UPDATE and DELETE statements" >&5
-printf %s "checking whether to support LIMIT on UPDATE and DELETE statements... " >&6; }
-if test "${enable_update_limit}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# See whether we should enable GEOPOLY
-# Check whether --enable-geopoly was given.
-if test ${enable_geopoly+y}
-then :
- enableval=$enable_geopoly; enable_geopoly=yes
-else $as_nop
- enable_geopoly=no
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support GEOPOLY" >&5
-printf %s "checking whether to support GEOPOLY... " >&6; }
-if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
- enable_rtree=yes
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# See whether we should enable RTREE
-# Check whether --enable-rtree was given.
-if test ${enable_rtree+y}
-then :
- enableval=$enable_rtree;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support RTREE" >&5
-printf %s "checking whether to support RTREE... " >&6; }
-if test "${enable_rtree}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# See whether we should enable the SESSION extension
-# Check whether --enable-session was given.
-if test ${enable_session+y}
-then :
- enableval=$enable_session;
-fi
-
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to support SESSION" >&5
-printf %s "checking whether to support SESSION... " >&6; }
-if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-printf "%s\n" "yes" >&6; }
-else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
-printf "%s\n" "no" >&6; }
-fi
-
-#########
-# attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter
-for option in $CFLAGS $CPPFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
- -DSQLITE_ENABLE*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
- esac
-done
-
-
-
-# attempt to remove any OMITS and ENABLES from the $(CFLAGS) parameter
-ac_temp_CFLAGS=""
-for option in $CFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_CFLAGS="$ac_temp_CFLAGS $option";;
- esac
-done
-CFLAGS=$ac_temp_CFLAGS
-
-
-# attempt to remove any OMITS and ENABLES from the $(CPPFLAGS) parameter
-ac_temp_CPPFLAGS=""
-for option in $CPPFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_CPPFLAGS="$ac_temp_CPPFLAGS $option";;
- esac
-done
-CPPFLAGS=$ac_temp_CPPFLAGS
-
-
-# attempt to remove any OMITS and ENABLES from the $(BUILD_CFLAGS) parameter
-ac_temp_BUILD_CFLAGS=""
-for option in $BUILD_CFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_BUILD_CFLAGS="$ac_temp_BUILD_CFLAGS $option";;
- esac
-done
-BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS
-
-
-#########
-# See whether we should use GCOV
-# Check whether --enable-gcov was given.
-if test ${enable_gcov+y}
-then :
- enableval=$enable_gcov;
-fi
-
-if test "${use_gcov}" = "yes" ; then
- USE_GCOV=1
-else
- USE_GCOV=0
-fi
-
-
-#########
-# Enable/disabled amalagamation line macros
-########
-AMALGAMATION_LINE_MACROS=--linemacros=0
-if test "${amalgamation_line_macros}" = "yes" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=1
-fi
-if test "${amalgamation_line_macros}" = "no" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=0
-fi
-
-
-#########
-# Output the config header
-ac_config_headers="$ac_config_headers sqlite_cfg.h"
-
-
-#########
-# Generate the output files.
-#
-
-ac_config_files="$ac_config_files Makefile sqlcipher.pc"
-
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems. If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
- for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
- eval ac_val=\$$ac_var
- case $ac_val in #(
- *${as_nl}*)
- case $ac_var in #(
- *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
- esac
- case $ac_var in #(
- _ | IFS | as_nl) ;; #(
- BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
- *) { eval $ac_var=; unset $ac_var;} ;;
- esac ;;
- esac
- done
-
- (set) 2>&1 |
- case $as_nl`(ac_space=' '; set) 2>&1` in #(
- *${as_nl}ac_space=\ *)
- # `set' does not quote correctly, so add quotes: double-quote
- # substitution turns \\\\ into \\, and sed turns \\ into \.
- sed -n \
- "s/'/'\\\\''/g;
- s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
- ;; #(
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
- ;;
- esac |
- sort
-) |
- sed '
- /^ac_cv_env_/b end
- t clear
- :clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
- t end
- s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
- :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
- if test -w "$cache_file"; then
- if test "x$cache_file" != "x/dev/null"; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
- if test ! -f "$cache_file" || test -h "$cache_file"; then
- cat confcache >"$cache_file"
- else
- case $cache_file in #(
- */* | ?:*)
- mv -f confcache "$cache_file"$$ &&
- mv -f "$cache_file"$$ "$cache_file" ;; #(
- *)
- mv -f confcache "$cache_file" ;;
- esac
- fi
- fi
- else
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
- fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-DEFS=-DHAVE_CONFIG_H
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
- # 1. Remove the extension, and $U if already installed.
- ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
- # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
- # will be set to the directory where LIBOBJS objects are built.
- as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
- as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-as_nop=:
-if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
-then :
- emulate sh
- NULLCMD=:
- # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
- # is contrary to our usage. Disable this feature.
- alias -g '${1+"$@"}'='"$@"'
- setopt NO_GLOB_SUBST
-else $as_nop
- case `(set -o) 2>/dev/null` in #(
- *posix*) :
- set -o posix ;; #(
- *) :
- ;;
-esac
-fi
-
-
-
-# Reset variables that may have inherited troublesome values from
-# the environment.
-
-# IFS needs to be set, to space, tab, and newline, in precisely that order.
-# (If _AS_PATH_WALK were called with IFS unset, it would have the
-# side effect of setting IFS to empty, thus disabling word splitting.)
-# Quoting is to prevent editors from complaining about space-tab.
-as_nl='
-'
-export as_nl
-IFS=" "" $as_nl"
-
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# Ensure predictable behavior from utilities with locale-dependent output.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# We cannot yet rely on "unset" to work, but we need these variables
-# to be unset--not just set to an empty or harmless value--now, to
-# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
-# also avoids known problems related to "unset" and subshell syntax
-# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
-for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
-do eval test \${$as_var+y} \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-
-# Ensure that fds 0, 1, and 2 are open.
-if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
-if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
-
-# The user is always right.
-if ${PATH_SEPARATOR+false} :; then
- PATH_SEPARATOR=:
- (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
- (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
- PATH_SEPARATOR=';'
- }
-fi
-
-
-# Find who we are. Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
- *[\\/]* ) as_myself=$0 ;;
- *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- case $as_dir in #(((
- '') as_dir=./ ;;
- */) ;;
- *) as_dir=$as_dir/ ;;
- esac
- test -r "$as_dir$0" && as_myself=$as_dir$0 && break
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
- as_myself=$0
-fi
-if test ! -f "$as_myself"; then
- printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
- exit 1
-fi
-
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
- as_status=$1; test $as_status -eq 0 && as_status=1
- if test "$4"; then
- as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
- fi
- printf "%s\n" "$as_me: error: $2" >&2
- as_fn_exit $as_status
-} # as_fn_error
-
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
- return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
- set +e
- as_fn_set_status $1
- exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
- { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
-then :
- eval 'as_fn_append ()
- {
- eval $1+=\$2
- }'
-else $as_nop
- as_fn_append ()
- {
- eval $1=\$$1\$2
- }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
-then :
- eval 'as_fn_arith ()
- {
- as_val=$(( $* ))
- }'
-else $as_nop
- as_fn_arith ()
- {
- as_val=`expr "$@" || test $? -eq 1`
- }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
- test "X`expr 00001 : '.*\(...\)'`" = X001; then
- as_expr=expr
-else
- as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
- as_basename=basename
-else
- as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
- as_dirname=dirname
-else
- as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
- X"$0" : 'X\(//\)$' \| \
- X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X/"$0" |
- sed '/^.*\/\([^/][^/]*\)\/*$/{
- s//\1/
- q
- }
- /^X\/\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\/\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-# Determine whether it's possible to make 'echo' print without a newline.
-# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
-# for compatibility with existing Makefiles.
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
- case `echo 'xy\c'` in
- *c*) ECHO_T=' ';; # ECHO_T is single tab character.
- xy) ECHO_C='\c';;
- *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
- ECHO_T=' ';;
- esac;;
-*)
- ECHO_N='-n';;
-esac
-
-# For backward compatibility with old third-party macros, we provide
-# the shell variables $as_echo and $as_echo_n. New code should use
-# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
-as_echo='printf %s\n'
-as_echo_n='printf %s'
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
- rm -f conf$$.dir/conf$$.file
-else
- rm -f conf$$.dir
- mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
- if ln -s conf$$.file conf$$ 2>/dev/null; then
- as_ln_s='ln -s'
- # ... but there are two gotchas:
- # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
- # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
- # In both cases, we have to default to `cp -pR'.
- ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
- as_ln_s='cp -pR'
- elif ln conf$$.file conf$$ 2>/dev/null; then
- as_ln_s=ln
- else
- as_ln_s='cp -pR'
- fi
-else
- as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
- case $as_dir in #(
- -*) as_dir=./$as_dir;;
- esac
- test -d "$as_dir" || eval $as_mkdir_p || {
- as_dirs=
- while :; do
- case $as_dir in #(
- *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
- *) as_qdir=$as_dir;;
- esac
- as_dirs="'$as_qdir' $as_dirs"
- as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$as_dir" : 'X\(//\)[^/]' \| \
- X"$as_dir" : 'X\(//\)$' \| \
- X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$as_dir" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- test -d "$as_dir" && break
- done
- test -z "$as_dirs" || eval "mkdir $as_dirs"
- } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
- as_mkdir_p='mkdir -p "$as_dir"'
-else
- test -d ./-p && rmdir ./-p
- as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
- test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by sqlcipher $as_me 3.44.2, which was
-generated by GNU Autoconf 2.71. Invocation command line was
-
- CONFIG_FILES = $CONFIG_FILES
- CONFIG_HEADERS = $CONFIG_HEADERS
- CONFIG_LINKS = $CONFIG_LINKS
- CONFIG_COMMANDS = $CONFIG_COMMANDS
- $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-case $ac_config_headers in *"
-"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
-esac
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-config_headers="$ac_config_headers"
-config_commands="$ac_config_commands"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration. Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
- -h, --help print this help, then exit
- -V, --version print version number and configuration settings, then exit
- --config print configuration, then exit
- -q, --quiet, --silent
- do not print progress messages
- -d, --debug don't remove temporary files
- --recheck update $as_me by reconfiguring in the same conditions
- --file=FILE[:TEMPLATE]
- instantiate the configuration file FILE
- --header=FILE[:TEMPLATE]
- instantiate the configuration header FILE
-
-Configuration files:
-$config_files
-
-Configuration headers:
-$config_headers
-
-Configuration commands:
-$config_commands
-
-Report bugs to the package provider."
-
-_ACEOF
-ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
-ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config='$ac_cs_config_escaped'
-ac_cs_version="\\
-sqlcipher config.status 3.44.2
-configured by $0, generated by GNU Autoconf 2.71,
- with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2021 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-INSTALL='$INSTALL'
-AWK='$AWK'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
- case $1 in
- --*=?*)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
- ac_shift=:
- ;;
- --*=)
- ac_option=`expr "X$1" : 'X\([^=]*\)='`
- ac_optarg=
- ac_shift=:
- ;;
- *)
- ac_option=$1
- ac_optarg=$2
- ac_shift=shift
- ;;
- esac
-
- case $ac_option in
- # Handling of the options.
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- ac_cs_recheck=: ;;
- --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- printf "%s\n" "$ac_cs_version"; exit ;;
- --config | --confi | --conf | --con | --co | --c )
- printf "%s\n" "$ac_cs_config"; exit ;;
- --debug | --debu | --deb | --de | --d | -d )
- debug=: ;;
- --file | --fil | --fi | --f )
- $ac_shift
- case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- '') as_fn_error $? "missing file argument" ;;
- esac
- as_fn_append CONFIG_FILES " '$ac_optarg'"
- ac_need_defaults=false;;
- --header | --heade | --head | --hea )
- $ac_shift
- case $ac_optarg in
- *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
- esac
- as_fn_append CONFIG_HEADERS " '$ac_optarg'"
- ac_need_defaults=false;;
- --he | --h)
- # Conflict between --help and --header
- as_fn_error $? "ambiguous option: \`$1'
-Try \`$0 --help' for more information.";;
- --help | --hel | -h )
- printf "%s\n" "$ac_cs_usage"; exit ;;
- -q | -quiet | --quiet | --quie | --qui | --qu | --q \
- | -silent | --silent | --silen | --sile | --sil | --si | --s)
- ac_cs_silent=: ;;
-
- # This is an error.
- -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
- *) as_fn_append ac_config_targets " $1"
- ac_need_defaults=false ;;
-
- esac
- shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
- exec 6>/dev/null
- ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
- set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
- shift
- \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
- CONFIG_SHELL='$SHELL'
- export CONFIG_SHELL
- exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
- echo
- sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
- printf "%s\n" "$ac_log"
-} >&5
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-#
-# INIT-COMMANDS
-#
-
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-sed_quote_subst='$sed_quote_subst'
-double_quote_subst='$double_quote_subst'
-delay_variable_subst='$delay_variable_subst'
-macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
-macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
-enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
-enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
-pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
-enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
-shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
-SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
-ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
-PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
-host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
-host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
-host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
-build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
-build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
-build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
-SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
-Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
-GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
-EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
-FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
-LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
-NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
-LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
-max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
-ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
-exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
-lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
-lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
-lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
-lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
-reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
-reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
-OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
-deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
-file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
-file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
-want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
-DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
-sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
-AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
-AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
-archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
-STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
-RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
-old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
-lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
-CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
-CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
-compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
-GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
-lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
-nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
-lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
-lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
-objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
-MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
-lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
-lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
-need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
-MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
-DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
-NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
-LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
-OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
-OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
-libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
-shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
-extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
-enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
-export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
-whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
-compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
-old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
-old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
-archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
-archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
-module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
-with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
-allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
-no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
-hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
-hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
-hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
-hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
-hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
-hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
-inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
-link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
-always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
-export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
-exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
-include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
-prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
-postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
-file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
-variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
-need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
-need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
-version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
-runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
-shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
-libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
-library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
-soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
-install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
-postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
-postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
-finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
-finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
-hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
-sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
-configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
-configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
-hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
-enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
-enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
-enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
-old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
-striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
-
-LTCC='$LTCC'
-LTCFLAGS='$LTCFLAGS'
-compiler='$compiler_DEFAULT'
-
-# A function that is used when there is no print builtin or printf.
-func_fallback_echo ()
-{
- eval 'cat <<_LTECHO_EOF
-\$1
-_LTECHO_EOF'
-}
-
-# Quote evaled strings.
-for var in SHELL \
-ECHO \
-PATH_SEPARATOR \
-SED \
-GREP \
-EGREP \
-FGREP \
-LD \
-NM \
-LN_S \
-lt_SP2NL \
-lt_NL2SP \
-reload_flag \
-OBJDUMP \
-deplibs_check_method \
-file_magic_cmd \
-file_magic_glob \
-want_nocaseglob \
-DLLTOOL \
-sharedlib_from_linklib_cmd \
-AR \
-AR_FLAGS \
-archiver_list_spec \
-STRIP \
-RANLIB \
-CC \
-CFLAGS \
-compiler \
-lt_cv_sys_global_symbol_pipe \
-lt_cv_sys_global_symbol_to_cdecl \
-lt_cv_sys_global_symbol_to_import \
-lt_cv_sys_global_symbol_to_c_name_address \
-lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
-lt_cv_nm_interface \
-nm_file_list_spec \
-lt_cv_truncate_bin \
-lt_prog_compiler_no_builtin_flag \
-lt_prog_compiler_pic \
-lt_prog_compiler_wl \
-lt_prog_compiler_static \
-lt_cv_prog_compiler_c_o \
-need_locks \
-MANIFEST_TOOL \
-DSYMUTIL \
-NMEDIT \
-LIPO \
-OTOOL \
-OTOOL64 \
-shrext_cmds \
-export_dynamic_flag_spec \
-whole_archive_flag_spec \
-compiler_needs_object \
-with_gnu_ld \
-allow_undefined_flag \
-no_undefined_flag \
-hardcode_libdir_flag_spec \
-hardcode_libdir_separator \
-exclude_expsyms \
-include_expsyms \
-file_list_spec \
-variables_saved_for_relink \
-libname_spec \
-library_names_spec \
-soname_spec \
-install_override_mode \
-finish_eval \
-old_striplib \
-striplib; do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[\\\\\\\`\\"\\\$]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-# Double-quote double-evaled strings.
-for var in reload_cmds \
-old_postinstall_cmds \
-old_postuninstall_cmds \
-old_archive_cmds \
-extract_expsyms_cmds \
-old_archive_from_new_cmds \
-old_archive_from_expsyms_cmds \
-archive_cmds \
-archive_expsym_cmds \
-module_cmds \
-module_expsym_cmds \
-export_symbols_cmds \
-prelink_cmds \
-postlink_cmds \
-postinstall_cmds \
-postuninstall_cmds \
-finish_cmds \
-sys_lib_search_path_spec \
-configure_time_dlsearch_path \
-configure_time_lt_sys_library_path; do
- case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
- *[\\\\\\\`\\"\\\$]*)
- eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
- ;;
- *)
- eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
- ;;
- esac
-done
-
-ac_aux_dir='$ac_aux_dir'
-
-# See if we are running on zsh, and set the options that allow our
-# commands through without removal of \ escapes INIT.
-if test -n "\${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
-fi
-
-
- PACKAGE='$PACKAGE'
- VERSION='$VERSION'
- RM='$RM'
- ofile='$ofile'
-
-
-
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
- case $ac_config_target in
- "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
- "sqlite_cfg.h") CONFIG_HEADERS="$CONFIG_HEADERS sqlite_cfg.h" ;;
- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
- "sqlcipher.pc") CONFIG_FILES="$CONFIG_FILES sqlcipher.pc" ;;
-
- *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
- esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used. Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
- test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
- test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
- test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands
-fi
-
-# Have a temporary directory for convenience. Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
- tmp= ac_tmp=
- trap 'exit_status=$?
- : "${ac_tmp:=$tmp}"
- { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
- trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
- tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
- test -d "$tmp"
-} ||
-{
- tmp=./conf$$-$RANDOM
- (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
- eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
- ac_cs_awk_cr='\\r'
-else
- ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
- echo "cat >conf$$subs.awk <<_ACEOF" &&
- echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
- echo "_ACEOF"
-} >conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
- . ./conf$$subs.sh ||
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
- ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
- if test $ac_delim_n = $ac_delim_num; then
- break
- elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
- else
- ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
- fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' >$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
- for (key in S) S_is_set[key] = 1
- FS = ""
-
-}
-{
- line = $ 0
- nfields = split(line, field, "@")
- substed = 0
- len = length(field[1])
- for (i = 2; i < nfields; i++) {
- key = field[i]
- keylen = length(key)
- if (S_is_set[key]) {
- value = S[key]
- line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
- len += length(value) + length(field[++i])
- substed = 1
- } else
- len += 1 + keylen
- }
-
- print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
- sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
- cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
- || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
-h
-s///
-s/^/:/
-s/[ ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[ ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[ ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-# Set up the scripts for CONFIG_HEADERS section.
-# No need to generate them if there are no CONFIG_HEADERS.
-# This happens for instance with `./config.status Makefile'.
-if test -n "$CONFIG_HEADERS"; then
-cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
-BEGIN {
-_ACEOF
-
-# Transform confdefs.h into an awk script `defines.awk', embedded as
-# here-document in config.status, that substitutes the proper values into
-# config.h.in to produce config.h.
-
-# Create a delimiter string that does not exist in confdefs.h, to ease
-# handling of long lines.
-ac_delim='%!_!# '
-for ac_last_try in false false :; do
- ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
- if test -z "$ac_tt"; then
- break
- elif $ac_last_try; then
- as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
- else
- ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
- fi
-done
-
-# For the awk script, D is an array of macro values keyed by name,
-# likewise P contains macro parameters if any. Preserve backslash
-# newline sequences.
-
-ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
-sed -n '
-s/.\{148\}/&'"$ac_delim"'/g
-t rset
-:rset
-s/^[ ]*#[ ]*define[ ][ ]*/ /
-t def
-d
-:def
-s/\\$//
-t bsnl
-s/["\\]/\\&/g
-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
-D["\1"]=" \3"/p
-s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
-d
-:bsnl
-s/["\\]/\\&/g
-s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
-D["\1"]=" \3\\\\\\n"\\/p
-t cont
-s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
-t cont
-d
-:cont
-n
-s/.\{148\}/&'"$ac_delim"'/g
-t clear
-:clear
-s/\\$//
-t bsnlc
-s/["\\]/\\&/g; s/^/"/; s/$/"/p
-d
-:bsnlc
-s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
-b cont
-' >$CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
- for (key in D) D_is_set[key] = 1
- FS = ""
-}
-/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
- line = \$ 0
- split(line, arg, " ")
- if (arg[1] == "#") {
- defundef = arg[2]
- mac1 = arg[3]
- } else {
- defundef = substr(arg[1], 2)
- mac1 = arg[2]
- }
- split(mac1, mac2, "(") #)
- macro = mac2[1]
- prefix = substr(line, 1, index(line, defundef) - 1)
- if (D_is_set[macro]) {
- # Preserve the white space surrounding the "#".
- print prefix "define", macro P[macro] D[macro]
- next
- } else {
- # Replace #undef with comments. This is necessary, for example,
- # in the case of _POSIX_SOURCE, which is predefined and required
- # on some systems where configure will not decide to define it.
- if (defundef == "undef") {
- print "/*", prefix defundef, macro, "*/"
- next
- }
- }
-}
-{ print }
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
- as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
-fi # test -n "$CONFIG_HEADERS"
-
-
-eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
-shift
-for ac_tag
-do
- case $ac_tag in
- :[FHLC]) ac_mode=$ac_tag; continue;;
- esac
- case $ac_mode$ac_tag in
- :[FHL]*:*);;
- :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
- :[FH]-) ac_tag=-:-;;
- :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
- esac
- ac_save_IFS=$IFS
- IFS=:
- set x $ac_tag
- IFS=$ac_save_IFS
- shift
- ac_file=$1
- shift
-
- case $ac_mode in
- :L) ac_source=$1;;
- :[FH])
- ac_file_inputs=
- for ac_f
- do
- case $ac_f in
- -) ac_f="$ac_tmp/stdin";;
- *) # Look for the file first in the build tree, then in the source tree
- # (if the path is not absolute). The absolute path cannot be DOS-style,
- # because $ac_f cannot contain `:'.
- test -f "$ac_f" ||
- case $ac_f in
- [\\/$]*) false;;
- *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
- esac ||
- as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
- esac
- case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
- as_fn_append ac_file_inputs " '$ac_f'"
- done
-
- # Let's still pretend it is `configure' which instantiates (i.e., don't
- # use $as_me), people would be surprised to read:
- # /* config.h. Generated by config.status. */
- configure_input='Generated from '`
- printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
- `' by configure.'
- if test x"$ac_file" != x-; then
- configure_input="$ac_file. $configure_input"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-printf "%s\n" "$as_me: creating $ac_file" >&6;}
- fi
- # Neutralize special characters interpreted by sed in replacement strings.
- case $configure_input in #(
- *\&* | *\|* | *\\* )
- ac_sed_conf_input=`printf "%s\n" "$configure_input" |
- sed 's/[\\\\&|]/\\\\&/g'`;; #(
- *) ac_sed_conf_input=$configure_input;;
- esac
-
- case $ac_tag in
- *:-:* | *:-) cat >"$ac_tmp/stdin" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
- esac
- ;;
- esac
-
- ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
- X"$ac_file" : 'X\(//\)[^/]' \| \
- X"$ac_file" : 'X\(//\)$' \| \
- X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-printf "%s\n" X"$ac_file" |
- sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
- s//\1/
- q
- }
- /^X\(\/\/\)[^/].*/{
- s//\1/
- q
- }
- /^X\(\/\/\)$/{
- s//\1/
- q
- }
- /^X\(\/\).*/{
- s//\1/
- q
- }
- s/.*/./; q'`
- as_dir="$ac_dir"; as_fn_mkdir_p
- ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
- ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
- # A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
- case $ac_top_builddir_sub in
- "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
- *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
- esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
- .) # We are building in place.
- ac_srcdir=.
- ac_top_srcdir=$ac_top_builddir_sub
- ac_abs_top_srcdir=$ac_pwd ;;
- [\\/]* | ?:[\\/]* ) # Absolute name.
- ac_srcdir=$srcdir$ac_dir_suffix;
- ac_top_srcdir=$srcdir
- ac_abs_top_srcdir=$srcdir ;;
- *) # Relative name.
- ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
- ac_top_srcdir=$ac_top_build_prefix$srcdir
- ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
- case $ac_mode in
- :F)
- #
- # CONFIG_FILE
- #
-
- case $INSTALL in
- [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
- *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
- esac
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
- p
- q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
- ac_datarootdir_hack='
- s&@datadir@&$datadir&g
- s&@docdir@&$docdir&g
- s&@infodir@&$infodir&g
- s&@localedir@&$localedir&g
- s&@mandir@&$mandir&g
- s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-s&@INSTALL@&$ac_INSTALL&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
- >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
- { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
- { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
- "$ac_tmp/out"`; test -z "$ac_out"; } &&
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&5
-printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined. Please make sure it is defined" >&2;}
-
- rm -f "$ac_tmp/stdin"
- case $ac_file in
- -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
- *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
- esac \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
- :H)
- #
- # CONFIG_HEADER
- #
- if test x"$ac_file" != x-; then
- {
- printf "%s\n" "/* $configure_input */" >&1 \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
- } >"$ac_tmp/config.h" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-printf "%s\n" "$as_me: $ac_file is unchanged" >&6;}
- else
- rm -f "$ac_file"
- mv "$ac_tmp/config.h" "$ac_file" \
- || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- fi
- else
- printf "%s\n" "/* $configure_input */" >&1 \
- && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
- || as_fn_error $? "could not create -" "$LINENO" 5
- fi
- ;;
-
- :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
-printf "%s\n" "$as_me: executing $ac_file commands" >&6;}
- ;;
- esac
-
-
- case $ac_file$ac_mode in
- "libtool":C)
-
- # See if we are running on zsh, and set the options that allow our
- # commands through without removal of \ escapes.
- if test -n "${ZSH_VERSION+set}"; then
- setopt NO_GLOB_SUBST
- fi
-
- cfgfile=${ofile}T
- trap "$RM \"$cfgfile\"; exit 1" 1 2 15
- $RM "$cfgfile"
-
- cat <<_LT_EOF >> "$cfgfile"
-#! $SHELL
-# Generated automatically by $as_me ($PACKAGE) $VERSION
-# NOTE: Changes made to this file will be lost: look at ltmain.sh.
-
-# Provide generalized library-building support services.
-# Written by Gordon Matzigkeit, 1996
-
-# Copyright (C) 2014 Free Software Foundation, Inc.
-# This is free software; see the source for copying conditions. There is NO
-# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
-# GNU Libtool is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of of the License, or
-# (at your option) any later version.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program or library that is built
-# using GNU Libtool, you may include this file under the same
-# distribution terms that you use for the rest of that program.
-#
-# GNU Libtool is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-
-# The names of the tagged configurations supported by this script.
-available_tags=''
-
-# Configured defaults for sys_lib_dlsearch_path munging.
-: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
-
-# ### BEGIN LIBTOOL CONFIG
-
-# Which release of libtool.m4 was used?
-macro_version=$macro_version
-macro_revision=$macro_revision
-
-# Whether or not to build shared libraries.
-build_libtool_libs=$enable_shared
-
-# Whether or not to build static libraries.
-build_old_libs=$enable_static
-
-# What type of objects to build.
-pic_mode=$pic_mode
-
-# Whether or not to optimize for fast installation.
-fast_install=$enable_fast_install
-
-# Shared archive member basename,for filename based shared library versioning on AIX.
-shared_archive_member_spec=$shared_archive_member_spec
-
-# Shell to use when invoking shell scripts.
-SHELL=$lt_SHELL
-
-# An echo program that protects backslashes.
-ECHO=$lt_ECHO
-
-# The PATH separator for the build system.
-PATH_SEPARATOR=$lt_PATH_SEPARATOR
-
-# The host system.
-host_alias=$host_alias
-host=$host
-host_os=$host_os
-
-# The build system.
-build_alias=$build_alias
-build=$build
-build_os=$build_os
-
-# A sed program that does not truncate output.
-SED=$lt_SED
-
-# Sed that helps us avoid accidentally triggering echo(1) options like -n.
-Xsed="\$SED -e 1s/^X//"
-
-# A grep program that handles long lines.
-GREP=$lt_GREP
-
-# An ERE matcher.
-EGREP=$lt_EGREP
-
-# A literal string matcher.
-FGREP=$lt_FGREP
-
-# A BSD- or MS-compatible name lister.
-NM=$lt_NM
-
-# Whether we need soft or hard links.
-LN_S=$lt_LN_S
-
-# What is the maximum length of a command?
-max_cmd_len=$max_cmd_len
-
-# Object file suffix (normally "o").
-objext=$ac_objext
-
-# Executable file suffix (normally "").
-exeext=$exeext
-
-# whether the shell understands "unset".
-lt_unset=$lt_unset
-
-# turn spaces into newlines.
-SP2NL=$lt_lt_SP2NL
-
-# turn newlines into spaces.
-NL2SP=$lt_lt_NL2SP
-
-# convert \$build file names to \$host format.
-to_host_file_cmd=$lt_cv_to_host_file_cmd
-
-# convert \$build files to toolchain format.
-to_tool_file_cmd=$lt_cv_to_tool_file_cmd
-
-# An object symbol dumper.
-OBJDUMP=$lt_OBJDUMP
-
-# Method to check whether dependent libraries are shared objects.
-deplibs_check_method=$lt_deplibs_check_method
-
-# Command to use when deplibs_check_method = "file_magic".
-file_magic_cmd=$lt_file_magic_cmd
-
-# How to find potential files when deplibs_check_method = "file_magic".
-file_magic_glob=$lt_file_magic_glob
-
-# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
-want_nocaseglob=$lt_want_nocaseglob
-
-# DLL creation program.
-DLLTOOL=$lt_DLLTOOL
-
-# Command to associate shared and link libraries.
-sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
-
-# The archiver.
-AR=$lt_AR
-
-# Flags to create an archive.
-AR_FLAGS=$lt_AR_FLAGS
-
-# How to feed a file listing to the archiver.
-archiver_list_spec=$lt_archiver_list_spec
-
-# A symbol stripping program.
-STRIP=$lt_STRIP
-
-# Commands used to install an old-style archive.
-RANLIB=$lt_RANLIB
-old_postinstall_cmds=$lt_old_postinstall_cmds
-old_postuninstall_cmds=$lt_old_postuninstall_cmds
-
-# Whether to use a lock for old archive extraction.
-lock_old_archive_extraction=$lock_old_archive_extraction
-
-# A C compiler.
-LTCC=$lt_CC
-
-# LTCC compiler flags.
-LTCFLAGS=$lt_CFLAGS
-
-# Take the output of nm and produce a listing of raw symbols and C names.
-global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
-
-# Transform the output of nm in a proper C declaration.
-global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
-
-# Transform the output of nm into a list of symbols to manually relocate.
-global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
-
-# Transform the output of nm in a C name address pair.
-global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
-
-# Transform the output of nm in a C name address pair when lib prefix is needed.
-global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
-
-# The name lister interface.
-nm_interface=$lt_lt_cv_nm_interface
-
-# Specify filename containing input files for \$NM.
-nm_file_list_spec=$lt_nm_file_list_spec
-
-# The root where to search for dependent libraries,and where our libraries should be installed.
-lt_sysroot=$lt_sysroot
-
-# Command to truncate a binary pipe.
-lt_truncate_bin=$lt_lt_cv_truncate_bin
-
-# The name of the directory that contains temporary libtool files.
-objdir=$objdir
-
-# Used to examine libraries when file_magic_cmd begins with "file".
-MAGIC_CMD=$MAGIC_CMD
-
-# Must we lock files when doing compilation?
-need_locks=$lt_need_locks
-
-# Manifest tool.
-MANIFEST_TOOL=$lt_MANIFEST_TOOL
-
-# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
-DSYMUTIL=$lt_DSYMUTIL
-
-# Tool to change global to local symbols on Mac OS X.
-NMEDIT=$lt_NMEDIT
-
-# Tool to manipulate fat objects and archives on Mac OS X.
-LIPO=$lt_LIPO
-
-# ldd/readelf like tool for Mach-O binaries on Mac OS X.
-OTOOL=$lt_OTOOL
-
-# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
-OTOOL64=$lt_OTOOL64
-
-# Old archive suffix (normally "a").
-libext=$libext
-
-# Shared library suffix (normally ".so").
-shrext_cmds=$lt_shrext_cmds
-
-# The commands to extract the exported symbol list from a shared archive.
-extract_expsyms_cmds=$lt_extract_expsyms_cmds
-
-# Variables whose values should be saved in libtool wrapper scripts and
-# restored at link time.
-variables_saved_for_relink=$lt_variables_saved_for_relink
-
-# Do we need the "lib" prefix for modules?
-need_lib_prefix=$need_lib_prefix
-
-# Do we need a version for libraries?
-need_version=$need_version
-
-# Library versioning type.
-version_type=$version_type
-
-# Shared library runtime path variable.
-runpath_var=$runpath_var
-
-# Shared library path variable.
-shlibpath_var=$shlibpath_var
-
-# Is shlibpath searched before the hard-coded library search path?
-shlibpath_overrides_runpath=$shlibpath_overrides_runpath
-
-# Format of library name prefix.
-libname_spec=$lt_libname_spec
-
-# List of archive names. First name is the real one, the rest are links.
-# The last name is the one that the linker finds with -lNAME
-library_names_spec=$lt_library_names_spec
-
-# The coded name of the library, if different from the real name.
-soname_spec=$lt_soname_spec
-
-# Permission mode override for installation of shared libraries.
-install_override_mode=$lt_install_override_mode
-
-# Command to use after installation of a shared archive.
-postinstall_cmds=$lt_postinstall_cmds
-
-# Command to use after uninstallation of a shared archive.
-postuninstall_cmds=$lt_postuninstall_cmds
-
-# Commands used to finish a libtool library installation in a directory.
-finish_cmds=$lt_finish_cmds
-
-# As "finish_cmds", except a single script fragment to be evaled but
-# not shown.
-finish_eval=$lt_finish_eval
-
-# Whether we should hardcode library paths into libraries.
-hardcode_into_libs=$hardcode_into_libs
-
-# Compile-time system search path for libraries.
-sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
-
-# Detected run-time system search path for libraries.
-sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
-
-# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
-configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
-
-# Whether dlopen is supported.
-dlopen_support=$enable_dlopen
-
-# Whether dlopen of programs is supported.
-dlopen_self=$enable_dlopen_self
-
-# Whether dlopen of statically linked programs is supported.
-dlopen_self_static=$enable_dlopen_self_static
-
-# Commands to strip libraries.
-old_striplib=$lt_old_striplib
-striplib=$lt_striplib
-
-
-# The linker used to build libraries.
-LD=$lt_LD
-
-# How to create reloadable object files.
-reload_flag=$lt_reload_flag
-reload_cmds=$lt_reload_cmds
-
-# Commands used to build an old-style archive.
-old_archive_cmds=$lt_old_archive_cmds
-
-# A language specific compiler.
-CC=$lt_compiler
-
-# Is the compiler the GNU compiler?
-with_gcc=$GCC
-
-# Compiler flag to turn off builtin functions.
-no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
-
-# Additional compiler flags for building library objects.
-pic_flag=$lt_lt_prog_compiler_pic
-
-# How to pass a linker flag through the compiler.
-wl=$lt_lt_prog_compiler_wl
-
-# Compiler flag to prevent dynamic linking.
-link_static_flag=$lt_lt_prog_compiler_static
-
-# Does compiler simultaneously support -c and -o options?
-compiler_c_o=$lt_lt_cv_prog_compiler_c_o
-
-# Whether or not to add -lc for building shared libraries.
-build_libtool_need_lc=$archive_cmds_need_lc
-
-# Whether or not to disallow shared libs when runtime libs are static.
-allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
-
-# Compiler flag to allow reflexive dlopens.
-export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
-
-# Compiler flag to generate shared objects directly from archives.
-whole_archive_flag_spec=$lt_whole_archive_flag_spec
-
-# Whether the compiler copes with passing no objects directly.
-compiler_needs_object=$lt_compiler_needs_object
-
-# Create an old-style archive from a shared archive.
-old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
-
-# Create a temporary old-style archive to link instead of a shared archive.
-old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
-
-# Commands used to build a shared archive.
-archive_cmds=$lt_archive_cmds
-archive_expsym_cmds=$lt_archive_expsym_cmds
-
-# Commands used to build a loadable module if different from building
-# a shared archive.
-module_cmds=$lt_module_cmds
-module_expsym_cmds=$lt_module_expsym_cmds
-
-# Whether we are building with GNU ld or not.
-with_gnu_ld=$lt_with_gnu_ld
-
-# Flag that allows shared libraries with undefined symbols to be built.
-allow_undefined_flag=$lt_allow_undefined_flag
-
-# Flag that enforces no undefined symbols.
-no_undefined_flag=$lt_no_undefined_flag
-
-# Flag to hardcode \$libdir into a binary during linking.
-# This must work even if \$libdir does not exist
-hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
-
-# Whether we need a single "-rpath" flag with a separated argument.
-hardcode_libdir_separator=$lt_hardcode_libdir_separator
-
-# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
-# DIR into the resulting binary.
-hardcode_direct=$hardcode_direct
-
-# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
-# DIR into the resulting binary and the resulting library dependency is
-# "absolute",i.e impossible to change by setting \$shlibpath_var if the
-# library is relocated.
-hardcode_direct_absolute=$hardcode_direct_absolute
-
-# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
-# into the resulting binary.
-hardcode_minus_L=$hardcode_minus_L
-
-# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
-# into the resulting binary.
-hardcode_shlibpath_var=$hardcode_shlibpath_var
-
-# Set to "yes" if building a shared library automatically hardcodes DIR
-# into the library and all subsequent libraries and executables linked
-# against it.
-hardcode_automatic=$hardcode_automatic
-
-# Set to yes if linker adds runtime paths of dependent libraries
-# to runtime path list.
-inherit_rpath=$inherit_rpath
-
-# Whether libtool must link a program against all its dependency libraries.
-link_all_deplibs=$link_all_deplibs
-
-# Set to "yes" if exported symbols are required.
-always_export_symbols=$always_export_symbols
-
-# The commands to list exported symbols.
-export_symbols_cmds=$lt_export_symbols_cmds
-
-# Symbols that should not be listed in the preloaded symbols.
-exclude_expsyms=$lt_exclude_expsyms
-
-# Symbols that must always be exported.
-include_expsyms=$lt_include_expsyms
-
-# Commands necessary for linking programs (against libraries) with templates.
-prelink_cmds=$lt_prelink_cmds
-
-# Commands necessary for finishing linking programs.
-postlink_cmds=$lt_postlink_cmds
-
-# Specify filename containing input files.
-file_list_spec=$lt_file_list_spec
-
-# How to hardcode a shared library path into an executable.
-hardcode_action=$hardcode_action
-
-# ### END LIBTOOL CONFIG
-
-_LT_EOF
-
- cat <<'_LT_EOF' >> "$cfgfile"
-
-# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
-
-# func_munge_path_list VARIABLE PATH
-# -----------------------------------
-# VARIABLE is name of variable containing _space_ separated list of
-# directories to be munged by the contents of PATH, which is string
-# having a format:
-# "DIR[:DIR]:"
-# string "DIR[ DIR]" will be prepended to VARIABLE
-# ":DIR[:DIR]"
-# string "DIR[ DIR]" will be appended to VARIABLE
-# "DIRP[:DIRP]::[DIRA:]DIRA"
-# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
-# "DIRA[ DIRA]" will be appended to VARIABLE
-# "DIR[:DIR]"
-# VARIABLE will be replaced by "DIR[ DIR]"
-func_munge_path_list ()
-{
- case x$2 in
- x)
- ;;
- *:)
- eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
- ;;
- x:*)
- eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
- ;;
- *::*)
- eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
- eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
- ;;
- *)
- eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
- ;;
- esac
-}
-
-
-# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
-func_cc_basename ()
-{
- for cc_temp in $*""; do
- case $cc_temp in
- compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
- distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
- \-*) ;;
- *) break;;
- esac
- done
- func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
-}
-
-
-# ### END FUNCTIONS SHARED WITH CONFIGURE
-
-_LT_EOF
-
- case $host_os in
- aix3*)
- cat <<\_LT_EOF >> "$cfgfile"
-# AIX sometimes has problems with the GCC collect2 program. For some
-# reason, if we set the COLLECT_NAMES environment variable, the problems
-# vanish in a puff of smoke.
-if test set != "${COLLECT_NAMES+set}"; then
- COLLECT_NAMES=
- export COLLECT_NAMES
-fi
-_LT_EOF
- ;;
- esac
-
-
-
-ltmain=$ac_aux_dir/ltmain.sh
-
-
- # We use sed instead of cat because bash on DJGPP gets confused if
- # if finds mixed CR/LF and LF-only lines. Since sed operates in
- # text mode, it properly converts lines to CR/LF. This bash problem
- # is reportedly fixed, but why not run on old versions too?
- sed '$q' "$ltmain" >> "$cfgfile" \
- || (rm -f "$cfgfile"; exit 1)
-
- mv -f "$cfgfile" "$ofile" ||
- (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
- chmod +x "$ofile"
-
- ;;
-
- esac
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
- as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded. So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status. When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
- ac_cs_success=:
- ac_config_status_args=
- test "$silent" = yes &&
- ac_config_status_args="$ac_config_status_args --quiet"
- exec 5>/dev/null
- $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
- exec 5>>config.log
- # Use ||, not &&, to avoid exiting from the if with $? = 1, which
- # would make configure fail if this is the last instruction.
- $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
+#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+#@@INITCHECK@@#
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index cbd3575f7a..0000000000
--- a/configure.ac
+++ /dev/null
@@ -1,968 +0,0 @@
-#
-# The build process allows for using a cross-compiler. But the default
-# action is to target the same platform that we are running on. The
-# configure script needs to discover the following properties of the
-# build and target systems:
-#
-# srcdir
-#
-# The is the name of the directory that contains the
-# "configure" shell script. All source files are
-# located relative to this directory.
-#
-# bindir
-#
-# The name of the directory where executables should be
-# written by the "install" target of the makefile.
-#
-# program_prefix
-#
-# Add this prefix to the names of all executables that run
-# on the target machine. Default: ""
-#
-# ENABLE_SHARED
-#
-# True if shared libraries should be generated.
-#
-# BUILD_CC
-#
-# The name of a command that is used to convert C
-# source files into executables that run on the build
-# platform.
-#
-# BUILD_CFLAGS
-#
-# Switches that the build compiler needs in order to construct
-# command-line programs.
-#
-# BUILD_LIBS
-#
-# Libraries that the build compiler needs in order to construct
-# command-line programs.
-#
-# BUILD_EXEEXT
-#
-# The filename extension for executables on the build
-# platform. "" for Unix and ".exe" for Windows.
-#
-# TCL_*
-#
-# Lots of values are read in from the tclConfig.sh script,
-# if that script is available. This values are used for
-# constructing and installing the TCL extension.
-#
-# TARGET_READLINE_LIBS
-#
-# This is the library directives passed to the target linker
-# that cause the executable to link against the readline library.
-# This might be a switch like "-lreadline" or pathnames of library
-# file like "../../src/libreadline.a".
-#
-# TARGET_READLINE_INC
-#
-# This variables define the directory that contain header
-# files for the readline library. If the compiler is able
-# to find on its own, then this can be blank.
-#
-# TARGET_EXEEXT
-#
-# The filename extension for executables on the
-# target platform. "" for Unix and ".exe" for windows.
-#
-# This configure.in file is easy to reuse on other projects. Just
-# change the argument to AC_INIT. And disable any features that
-# you don't need (for example BLT) by erasing or commenting out
-# the corresponding code.
-#
-AC_INIT(sqlcipher, m4_esyscmd([cat VERSION | tr -d '\n']))
-
-dnl Make sure the local VERSION file matches this configure script
-sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'`
-if test "$PACKAGE_VERSION" != "$sqlite_version_sanity_check" ; then
-AC_MSG_ERROR([configure script is out of date:
- configure \$PACKAGE_VERSION = $PACKAGE_VERSION
- top level VERSION file = $sqlite_version_sanity_check
-please regen with autoconf])
-fi
-
-#########
-# Programs needed
-#
-LT_INIT
-AC_PROG_INSTALL
-
-#########
-# Enable large file support (if special flags are necessary)
-#
-AC_SYS_LARGEFILE
-
-#########
-# Check for needed/wanted data types
-AC_CHECK_TYPES([int8_t, int16_t, int32_t, int64_t, intptr_t, uint8_t,
- uint16_t, uint32_t, uint64_t, uintptr_t])
-
-#########
-# Check for needed/wanted headers
-AC_CHECK_HEADERS([sys/types.h stdlib.h stdint.h inttypes.h malloc.h])
-
-#########
-# Figure out whether or not we have these functions
-#
-AC_CHECK_FUNCS([fdatasync gmtime_r isnan localtime_r localtime_s malloc_usable_size strchrnul usleep utime pread pread64 pwrite pwrite64])
-
-#########
-# By default, we use the amalgamation (this may be changed below...)
-#
-USE_AMALGAMATION=1
-
-#########
-# See whether we can run specific tclsh versions known to work well;
-# if not, then we fall back to plain tclsh.
-# TODO: try other versions before falling back?
-#
-AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none)
-if test "$TCLSH_CMD" = "none"; then
- # If we can't find a local tclsh, then building the amalgamation will fail.
- # We act as though --disable-amalgamation has been used.
- echo "Warning: can't find tclsh - defaulting to non-amalgamation build."
- USE_AMALGAMATION=0
- TCLSH_CMD="tclsh"
-fi
-AC_SUBST(TCLSH_CMD)
-
-AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])
-if test "x${TCLLIBDIR+set}" != "xset" ; then
- TCLLIBDIR='$(libdir)'
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}` ; do
- if test -d $i ; then
- TCLLIBDIR=$i
- break
- fi
- done
- TCLLIBDIR="${TCLLIBDIR}/sqlite3"
-fi
-
-#########
-# Set up an appropriate program prefix
-#
-if test "$program_prefix" = "NONE"; then
- program_prefix=""
-fi
-AC_SUBST(program_prefix)
-
-VERSION=[`cat $srcdir/VERSION | sed 's/^\([0-9]*\.*[0-9]*\).*/\1/'`]
-AC_MSG_NOTICE(Version set to $VERSION)
-AC_SUBST(VERSION)
-RELEASE=`cat $srcdir/VERSION`
-AC_MSG_NOTICE(Release set to $RELEASE)
-AC_SUBST(RELEASE)
-
-##########
-# Handle --with-wasi-sdk=DIR
-#
-# This must be early because it changes the toolchain.
-#
-AC_ARG_WITH(wasi-sdk,
-AS_HELP_STRING([--with-wasi-sdk=DIR],
- [directory containing the WASI SDK. Triggers cross-compile to WASM.]), with_wasisdk=${withval})
-AC_MSG_CHECKING([for WASI SDK directory])
-AC_CACHE_VAL(ac_cv_c_wasi_sdk,[
- # First check to see if --with-tcl was specified.
- if test x"${with_wasi_sdk}" != x ; then
- if ! test -d "${with_wasi_sdk}" ; then
- AC_MSG_ERROR([${with_wasi_sdk} directory doesn't exist])
- fi
- AC_MSG_RESULT([${with_wasi_sdk}: using wasi-sdk clang, disabling: tcl, CLI shell, DLL])
- use_wasi_sdk=yes
- else
- use_wasi_sdk=no
- fi
-])
-if test "${use_wasi_sdk}" = "no" ; then
- HAVE_WASI_SDK=""
- AC_MSG_RESULT([no])
-else
- HAVE_WASI_SDK=1
-# Changing --host and --target have no effect here except to possibly
-# cause confusion. autoconf has finished processing them by this
-# point.
-#
-# host_alias=wasm32-wasi
-# target=wasm32-wasi
-#
-# Merely changing CC and LD to the wasi-sdk's is enough to get
-# sqlite3.o building in WASM format.
- CC="${with_wasi_sdk}/bin/clang"
- LD="${with_wasi_sdk}/bin/wasm-ld"
- RANLIB="${with_wasi_sdk}/bin/llvm-ranlib"
- cross_compiling=yes
- enable_threadsafe=no
- use_tcl=no
- enable_tcl=no
- # libtool is apparently hard-coded to use gcc for linking DLLs, so
- # we disable the DLL build...
- enable_shared=no
- AC_MSG_RESULT([yes])
-fi
-AC_SUBST(HAVE_WASI_SDK)
-
-
-#########
-# Locate a compiler for the build machine. This compiler should
-# generate command-line programs that run on the build machine.
-#
-if test x"$cross_compiling" = xno; then
- BUILD_CC=$CC
- BUILD_CFLAGS=$CFLAGS
-else
- if test "${BUILD_CC+set}" != set; then
- AC_CHECK_PROGS(BUILD_CC, gcc cc cl)
- fi
- if test "${BUILD_CFLAGS+set}" != set; then
- BUILD_CFLAGS="-g"
- fi
-fi
-AC_SUBST(BUILD_CC)
-
-##########
-# Do we want to support multithreaded use of sqlite
-#
-AC_ARG_ENABLE(threadsafe,
-AS_HELP_STRING([--disable-threadsafe],[Disable mutexing]))
-AC_MSG_CHECKING([whether to support threadsafe operation])
-if test "$enable_threadsafe" = "no"; then
- SQLITE_THREADSAFE=0
- AC_MSG_RESULT([no])
-else
- SQLITE_THREADSAFE=1
- AC_MSG_RESULT([yes])
-fi
-AC_SUBST(SQLITE_THREADSAFE)
-
-if test "$SQLITE_THREADSAFE" = "1"; then
- AC_SEARCH_LIBS(pthread_create, pthread)
- AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
-fi
-
-##########
-# Which crypto library do we use
-#
-AC_ARG_WITH([crypto-lib],
-AC_HELP_STRING([--with-crypto-lib],[Specify which crypto library to use]),
-crypto_lib=$withval)
-AC_MSG_CHECKING([for crypto library to use])
-if test "$crypto_lib" = "none"; then
- AC_MSG_RESULT([none])
-else
- if test "$crypto_lib" = "commoncrypto"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_CC"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_CC"
- AC_MSG_RESULT([commoncrypto])
- else
- if test "$crypto_lib" = "libtomcrypt"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_LIBTOMCRYPT"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_LIBTOMCRYPT"
- AC_MSG_RESULT([libtomcrypt])
- AC_CHECK_LIB([tomcrypt], [register_cipher], ,
- AC_MSG_ERROR([Library crypto not found. Install libtomcrypt!"]))
- else
- if test "$crypto_lib" = "nss"; then
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_NSS"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_NSS"
- AC_MSG_RESULT([nss3])
- AC_CHECK_LIB([nss3], [PK11_Decrypt], ,
- AC_MSG_ERROR([Library crypto not found. Install nss!"]))
- else
- CFLAGS="$CFLAGS -DSQLCIPHER_CRYPTO_OPENSSL"
- BUILD_CFLAGS="$BUILD_CFLAGS -DSQLCIPHER_CRYPTO_OPENSSL"
- AC_MSG_RESULT([openssl])
- AC_CHECK_LIB([crypto], [HMAC_Init_ex], ,
- AC_MSG_ERROR([Library crypto not found. Install openssl!"]))
- fi
- fi
- fi
-fi
-
-##########
-# Do we want to allow a connection created in one thread to be used
-# in another thread. This does not work on many Linux systems (ex: RedHat 9)
-# due to bugs in the threading implementations. This is thus off by default.
-#
-AC_ARG_ENABLE(cross-thread-connections,
-AC_HELP_STRING([--enable-cross-thread-connections],[Allow connection sharing across threads]),,enable_xthreadconnect=no)
-AC_MSG_CHECKING([whether to allow connections to be shared across threads])
-if test "$enable_xthreadconnect" = "no"; then
- XTHREADCONNECT=''
- AC_MSG_RESULT([no])
-else
- XTHREADCONNECT='-DSQLITE_ALLOW_XTHREAD_CONNECT=1'
- AC_MSG_RESULT([yes])
-fi
-AC_SUBST(XTHREADCONNECT)
-
-##########
-# Do we want to support release
-#
-AC_ARG_ENABLE(releasemode,
-AS_HELP_STRING([--enable-releasemode],[Support libtool link to release mode]),,enable_releasemode=no)
-AC_MSG_CHECKING([whether to support shared library linked as release mode or not])
-if test "$enable_releasemode" = "no"; then
- ALLOWRELEASE=""
- AC_MSG_RESULT([no])
-else
- ALLOWRELEASE="-release `cat $srcdir/VERSION`"
- AC_MSG_RESULT([yes])
-fi
-AC_SUBST(ALLOWRELEASE)
-
-##########
-# Do we want temporary databases in memory
-#
-AC_ARG_ENABLE(tempstore,
-AS_HELP_STRING([--enable-tempstore],[Use an in-ram database for temporary tables (never,no,yes,always)]),,enable_tempstore=no)
-AC_MSG_CHECKING([whether to use an in-ram database for temporary tables])
-case "$enable_tempstore" in
- never )
- TEMP_STORE=0
- AC_MSG_RESULT([never])
- ;;
- no )
- TEMP_STORE=1
- AC_MSG_RESULT([no])
- ;;
- yes )
- TEMP_STORE=2
- AC_MSG_RESULT([yes])
- ;;
- always )
- TEMP_STORE=3
- AC_MSG_RESULT([always])
- ;;
- * )
- TEMP_STORE=1
- AC_MSG_RESULT([no])
- ;;
-esac
-
-AC_SUBST(TEMP_STORE)
-
-###########
-# Lots of things are different if we are compiling for Windows using
-# the CYGWIN environment. So check for that special case and handle
-# things accordingly.
-#
-AC_MSG_CHECKING([if executables have the .exe suffix])
-if test "$config_BUILD_EXEEXT" = ".exe"; then
- CYGWIN=yes
- AC_MSG_RESULT(yes)
-else
- AC_MSG_RESULT(unknown)
-fi
-if test "$CYGWIN" != "yes"; then
- m4_warn([obsolete],
-[AC_CYGWIN is obsolete: use AC_CANONICAL_HOST and check if $host_os
-matches *cygwin*])dnl
-AC_CANONICAL_HOST
-case $host_os in
- *cygwin* ) CYGWIN=yes;;
- * ) CYGWIN=no;;
-esac
-
-fi
-if test "$CYGWIN" = "yes"; then
- BUILD_EXEEXT=.exe
-else
- BUILD_EXEEXT=$EXEEXT
-fi
-if test x"$cross_compiling" = xno; then
- TARGET_EXEEXT=$BUILD_EXEEXT
-else
- TARGET_EXEEXT=$config_TARGET_EXEEXT
-fi
-if test "$TARGET_EXEEXT" = ".exe"; then
- SQLITE_OS_UNIX=0
- SQLITE_OS_WIN=1
- CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
-else
- SQLITE_OS_UNIX=1
- SQLITE_OS_WIN=0
- CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
-fi
-
-AC_SUBST(BUILD_EXEEXT)
-AC_SUBST(SQLITE_OS_UNIX)
-AC_SUBST(SQLITE_OS_WIN)
-AC_SUBST(TARGET_EXEEXT)
-
-##########
-# Figure out all the parameters needed to compile against Tcl.
-#
-# This code is derived from the SC_PATH_TCLCONFIG and SC_LOAD_TCLCONFIG
-# macros in the in the tcl.m4 file of the standard TCL distribution.
-# Those macros could not be used directly since we have to make some
-# minor changes to accomodate systems that do not have TCL installed.
-#
-AC_ARG_ENABLE(tcl, AS_HELP_STRING([--disable-tcl],[do not build TCL extension]),
- [use_tcl=$enableval],[use_tcl=yes])
-if test "${use_tcl}" = "yes" ; then
- AC_ARG_WITH(tcl, AS_HELP_STRING([--with-tcl=DIR],[directory containing tcl configuration (tclConfig.sh)]), with_tclconfig=${withval})
- AC_MSG_CHECKING([for Tcl configuration])
- AC_CACHE_VAL(ac_cv_c_tclconfig,[
- # First check to see if --with-tcl was specified.
- if test x"${with_tclconfig}" != x ; then
- if test -f "${with_tclconfig}/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)`
- else
- AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh])
- fi
- fi
-
- # Start autosearch by asking tclsh
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD}`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # On ubuntu 14.10, $auto_path on tclsh is not quite correct.
- # So try again after applying corrections.
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in `echo 'puts stdout $auto_path' | ${TCLSH_CMD} | sed 's,/tcltk/tcl,/tcl,g'`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # Recent versions of Xcode on Macs hid the tclConfig.sh file
- # in a strange place.
- if test x"${ac_cv_c_tclconfig}" = x ; then
- if test x"$cross_compiling" = xno; then
- for i in /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX*.sdk/usr/lib
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig="$i"
- break
- fi
- done
- fi
- fi
-
- # then check for a private Tcl installation
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ../tcl \
- `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../tcl \
- `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \
- ../../../tcl \
- `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null`
- do
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
- break
- fi
- done
- fi
-
- # check in a few common install locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- `ls -d ${libdir} 2>/dev/null` \
- `ls -d /usr/local/lib 2>/dev/null` \
- `ls -d /usr/contrib/lib 2>/dev/null` \
- `ls -d /usr/lib 2>/dev/null`
- do
- if test -f "$i/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i; pwd)`
- break
- fi
- done
- fi
-
- # check in a few other private locations
- if test x"${ac_cv_c_tclconfig}" = x ; then
- for i in \
- ${srcdir}/../tcl \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \
- `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null`
- do
- if test -f "$i/unix/tclConfig.sh" ; then
- ac_cv_c_tclconfig=`(cd $i/unix; pwd)`
- break
- fi
- done
- fi
- ])
-
- if test x"${ac_cv_c_tclconfig}" = x ; then
- use_tcl=no
- AC_MSG_WARN(Can't find Tcl configuration definitions)
- AC_MSG_WARN(*** Without Tcl the regression tests cannot be executed ***)
- AC_MSG_WARN(*** Consider using --with-tcl=... to define location of Tcl ***)
- else
- TCL_BIN_DIR=${ac_cv_c_tclconfig}
- AC_MSG_RESULT(found $TCL_BIN_DIR/tclConfig.sh)
-
- AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh])
- if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then
- AC_MSG_RESULT([loading])
- . $TCL_BIN_DIR/tclConfig.sh
- else
- AC_MSG_RESULT([file not found])
- fi
-
- #
- # If the TCL_BIN_DIR is the build directory (not the install directory),
- # then set the common variable name to the value of the build variables.
- # For example, the variable TCL_LIB_SPEC will be set to the value
- # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC
- # instead of TCL_BUILD_LIB_SPEC since it will work with both an
- # installed and uninstalled version of Tcl.
- #
-
- if test -f $TCL_BIN_DIR/Makefile ; then
- TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC}
- TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC}
- TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH}
- fi
-
- #
- # eval is required to do the TCL_DBGX substitution
- #
-
- eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\""
- eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\""
- eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\""
-
- eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\""
- eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\""
- eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\""
-
- AC_SUBST(TCL_VERSION)
- AC_SUBST(TCL_BIN_DIR)
- AC_SUBST(TCL_SRC_DIR)
- AC_SUBST(TCL_INCLUDE_SPEC)
-
- AC_SUBST(TCL_LIB_FILE)
- AC_SUBST(TCL_LIB_FLAG)
- AC_SUBST(TCL_LIB_SPEC)
-
- AC_SUBST(TCL_STUB_LIB_FILE)
- AC_SUBST(TCL_STUB_LIB_FLAG)
- AC_SUBST(TCL_STUB_LIB_SPEC)
- AC_SUBST(TCL_SHLIB_SUFFIX)
- fi
-fi
-if test "${use_tcl}" = "no" ; then
- HAVE_TCL=""
-else
- HAVE_TCL=1
-fi
-AC_SUBST(HAVE_TCL)
-
-##########
-# Figure out what C libraries are required to compile programs
-# that use "readline()" library.
-#
-TARGET_READLINE_LIBS=""
-TARGET_READLINE_INC=""
-TARGET_HAVE_READLINE=0
-TARGET_HAVE_EDITLINE=0
-AC_ARG_ENABLE([editline],
- [AS_HELP_STRING([--enable-editline],[enable BSD editline support])],
- [with_editline=$enableval],
- [with_editline=auto])
-AC_ARG_ENABLE([readline],
- [AS_HELP_STRING([--disable-readline],[disable readline support])],
- [with_readline=$enableval],
- [with_readline=auto])
-
-if test x"$with_editline" != xno; then
- sLIBS=$LIBS
- LIBS=""
- TARGET_HAVE_EDITLINE=1
- AC_SEARCH_LIBS(readline,edit,[with_readline=no],[TARGET_HAVE_EDITLINE=0])
- TARGET_READLINE_LIBS=$LIBS
- LIBS=$sLIBS
-fi
-if test x"$with_readline" != xno; then
- found="yes"
-
- AC_ARG_WITH([readline-lib],
- [AS_HELP_STRING([--with-readline-lib],[specify readline library])],
- [with_readline_lib=$withval],
- [with_readline_lib="auto"])
- if test "x$with_readline_lib" = xauto; then
- save_LIBS="$LIBS"
- LIBS=""
- AC_SEARCH_LIBS(tgetent, [readline ncurses curses termcap], [term_LIBS="$LIBS"], [term_LIBS=""])
- AC_CHECK_LIB([readline], [readline], [TARGET_READLINE_LIBS="-lreadline"], [found="no"])
- TARGET_READLINE_LIBS="$TARGET_READLINE_LIBS $term_LIBS"
- LIBS="$save_LIBS"
- else
- TARGET_READLINE_LIBS="$with_readline_lib"
- fi
-
- AC_ARG_WITH([readline-inc],
- [AS_HELP_STRING([--with-readline-inc],[specify readline include paths])],
- [with_readline_inc=$withval],
- [with_readline_inc="auto"])
- if test "x$with_readline_inc" = xauto; then
- AC_CHECK_HEADER(readline.h, [found="yes"], [
- found="no"
- if test "$cross_compiling" != yes; then
- for dir in /usr /usr/local /usr/local/readline /usr/contrib /mingw; do
- for subdir in include include/readline; do
- AC_CHECK_FILE($dir/$subdir/readline.h, found=yes)
- if test "$found" = "yes"; then
- TARGET_READLINE_INC="-I$dir/$subdir"
- break
- fi
- done
- test "$found" = "yes" && break
- done
- fi
- ])
- else
- TARGET_READLINE_INC="$with_readline_inc"
- fi
-
- if test x"$found" = xno; then
- TARGET_READLINE_LIBS=""
- TARGET_READLINE_INC=""
- TARGET_HAVE_READLINE=0
- else
- TARGET_HAVE_READLINE=1
- fi
-fi
-AC_ARG_WITH([linenoise],
- [AS_HELP_STRING([--with-linenoise=DIR],[source directory for linenoise library])],
- [with_linenoise=$withval],
- [with_linenoise="no"])
-if test "x$with_linenoise" != "xno"; then
- TARGET_HAVE_READLINE=0
- TARGET_HAVE_EDITLINE=0
- TARGET_HAVE_LINENOISE=1
- TARGET_READLINE_INC="-I${with_linenoise}"
- TARGET_READLINE_LIBS="${with_linenoise}/linenoise.c"
- echo "using linenoise source code at ${with_linenoise}"
-else
- TARGET_HAVE_LINENOISE=0
- echo "not using linenoise"
-fi
-
-AC_SUBST(TARGET_READLINE_LIBS)
-AC_SUBST(TARGET_READLINE_INC)
-AC_SUBST(TARGET_HAVE_READLINE)
-AC_SUBST(TARGET_HAVE_EDITLINE)
-AC_SUBST(TARGET_HAVE_LINENOISE)
-
-
-##########
-# Figure out what C libraries are required to compile programs
-# that use "fdatasync()" function.
-#
-AC_SEARCH_LIBS(fdatasync, [rt])
-
-#########
-# check for debug enabled
-AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug],[enable debugging & verbose explain]))
-AC_MSG_CHECKING([build type])
-if test "${enable_debug}" = "yes" ; then
- TARGET_DEBUG="-DSQLITE_DEBUG=1 -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE -O0 -Wall"
- AC_MSG_RESULT([debug])
-else
- TARGET_DEBUG="-DNDEBUG"
- AC_MSG_RESULT([release])
-fi
-AC_SUBST(TARGET_DEBUG)
-
-#########
-# See whether we should use the amalgamation to build
-
-AC_ARG_ENABLE(amalgamation, AS_HELP_STRING([--disable-amalgamation],
- [Disable the amalgamation and instead build all files separately]))
-if test "${enable_amalgamation}" = "no" ; then
- USE_AMALGAMATION=0
-fi
-AC_SUBST(USE_AMALGAMATION)
-
-#########
-# By default, amalgamation sqlite3.c will have #line directives.
-# This is a build option not shown by ./configure --help
-# To control it, use configure option: amalgamation_line_macros=?
-# where ? is no to suppress #line directives or yes to create them.
-AMALGAMATION_LINE_MACROS=--linemacros=1
-AC_ARG_VAR(amalgamation_line_macros,)
-AC_SUBST(AMALGAMATION_LINE_MACROS)
-if test "${amalgamation_line_macros+set}" = set; then :
- enableval=$amalgamation_line_macros;
-fi
-if test "${amalgamation_line_macros}" = "yes" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=1
-fi
-if test "${amalgamation_line_macros}" = "no" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=0
-fi
-
-#########
-# Look for zlib. Only needed by extensions and by the sqlite3.exe shell
-AC_CHECK_HEADERS(zlib.h)
-AC_SEARCH_LIBS(deflate, z, [HAVE_ZLIB="-DSQLITE_HAVE_ZLIB=1"], [HAVE_ZLIB=""])
-AC_SUBST(HAVE_ZLIB)
-
-#########
-# See whether we should allow loadable extensions
-AC_ARG_ENABLE(load-extension, AS_HELP_STRING([--disable-load-extension],
- [Disable loading of external extensions]),,[enable_load_extension=yes])
-if test "${enable_load_extension}" = "yes" ; then
- OPT_FEATURE_FLAGS=""
- AC_SEARCH_LIBS(dlopen, dl)
-else
- OPT_FEATURE_FLAGS="-DSQLITE_OMIT_LOAD_EXTENSION=1"
-fi
-
-##########
-# Do we want to support math functions
-#
-AC_ARG_ENABLE(math,
-AS_HELP_STRING([--disable-math],[Disable math functions]))
-AC_MSG_CHECKING([whether to support math functions])
-if test "$enable_math" = "no"; then
- AC_MSG_RESULT([no])
-else
- AC_MSG_RESULT([yes])
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MATH_FUNCTIONS"
- AC_SEARCH_LIBS(ceil, m)
-fi
-
-##########
-# Do we want to support JSON functions
-#
-AC_ARG_ENABLE(json,
-AS_HELP_STRING([--disable-json],[Disable JSON functions]))
-AC_MSG_CHECKING([whether to support JSON functions])
-if test "$enable_json" = "no"; then
- AC_MSG_RESULT([no])
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_OMIT_JSON"
-else
- AC_MSG_RESULT([yes])
-fi
-
-########
-# The --enable-all argument is short-hand to enable
-# multiple extensions.
-AC_ARG_ENABLE(all, AS_HELP_STRING([--enable-all],
- [Enable FTS4, FTS5, Geopoly, RTree, Sessions]))
-
-##########
-# Do we want to support memsys3 and/or memsys5
-#
-AC_ARG_ENABLE(memsys5,
- AS_HELP_STRING([--enable-memsys5],[Enable MEMSYS5]))
-AC_MSG_CHECKING([whether to support MEMSYS5])
-if test "${enable_memsys5}" = "yes"; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS5"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-AC_ARG_ENABLE(memsys3,
- AS_HELP_STRING([--enable-memsys3],[Enable MEMSYS3]))
-AC_MSG_CHECKING([whether to support MEMSYS3])
-if test "${enable_memsys3}" = "yes" -a "${enable_memsys5}" = "no"; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_MEMSYS3"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# See whether we should enable Full Text Search extensions
-AC_ARG_ENABLE(fts3, AS_HELP_STRING([--enable-fts3],
- [Enable the FTS3 extension]))
-AC_MSG_CHECKING([whether to support FTS3])
-if test "${enable_fts3}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS3"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-AC_ARG_ENABLE(fts4, AS_HELP_STRING([--enable-fts4],
- [Enable the FTS4 extension]))
-AC_MSG_CHECKING([whether to support FTS4])
-if test "${enable_fts4}" = "yes" -o "${enable_all}" = "yes" ; then
- AC_MSG_RESULT([yes])
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS4"
- AC_SEARCH_LIBS([log],[m])
-else
- AC_MSG_RESULT([no])
-fi
-AC_ARG_ENABLE(fts5, AS_HELP_STRING([--enable-fts5],
- [Enable the FTS5 extension]))
-AC_MSG_CHECKING([whether to support FTS5])
-if test "${enable_fts5}" = "yes" -o "${enable_all}" = "yes" ; then
- AC_MSG_RESULT([yes])
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_FTS5"
- AC_SEARCH_LIBS([log],[m])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# See whether we should enable the LIMIT clause on UPDATE and DELETE
-# statements.
-AC_ARG_ENABLE(update-limit, AS_HELP_STRING([--enable-update-limit],
- [Enable the UPDATE/DELETE LIMIT clause]))
-AC_MSG_CHECKING([whether to support LIMIT on UPDATE and DELETE statements])
-if test "${enable_update_limit}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# See whether we should enable GEOPOLY
-AC_ARG_ENABLE(geopoly, AS_HELP_STRING([--enable-geopoly],
- [Enable the GEOPOLY extension]),
- [enable_geopoly=yes],[enable_geopoly=no])
-AC_MSG_CHECKING([whether to support GEOPOLY])
-if test "${enable_geopoly}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY"
- enable_rtree=yes
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# See whether we should enable RTREE
-AC_ARG_ENABLE(rtree, AS_HELP_STRING([--enable-rtree],
- [Enable the RTREE extension]))
-AC_MSG_CHECKING([whether to support RTREE])
-if test "${enable_rtree}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_RTREE"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# See whether we should enable the SESSION extension
-AC_ARG_ENABLE(session, AS_HELP_STRING([--enable-session],
- [Enable the SESSION extension]))
-AC_MSG_CHECKING([whether to support SESSION])
-if test "${enable_session}" = "yes" -o "${enable_all}" = "yes" ; then
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_SESSION"
- OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_PREUPDATE_HOOK"
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
-#########
-# attempt to duplicate any OMITS and ENABLES into the ${OPT_FEATURE_FLAGS} parameter
-for option in $CFLAGS $CPPFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
- -DSQLITE_ENABLE*) OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS $option";;
- esac
-done
-AC_SUBST(OPT_FEATURE_FLAGS)
-
-
-# attempt to remove any OMITS and ENABLES from the $(CFLAGS) parameter
-ac_temp_CFLAGS=""
-for option in $CFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_CFLAGS="$ac_temp_CFLAGS $option";;
- esac
-done
-CFLAGS=$ac_temp_CFLAGS
-
-
-# attempt to remove any OMITS and ENABLES from the $(CPPFLAGS) parameter
-ac_temp_CPPFLAGS=""
-for option in $CPPFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_CPPFLAGS="$ac_temp_CPPFLAGS $option";;
- esac
-done
-CPPFLAGS=$ac_temp_CPPFLAGS
-
-
-# attempt to remove any OMITS and ENABLES from the $(BUILD_CFLAGS) parameter
-ac_temp_BUILD_CFLAGS=""
-for option in $BUILD_CFLAGS
-do
- case $option in
- -DSQLITE_OMIT*) ;;
- -DSQLITE_ENABLE*) ;;
- *) ac_temp_BUILD_CFLAGS="$ac_temp_BUILD_CFLAGS $option";;
- esac
-done
-BUILD_CFLAGS=$ac_temp_BUILD_CFLAGS
-
-
-#########
-# See whether we should use GCOV
-AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],
- [Enable coverage testing using gcov]))
-if test "${use_gcov}" = "yes" ; then
- USE_GCOV=1
-else
- USE_GCOV=0
-fi
-AC_SUBST(USE_GCOV)
-
-#########
-# Enable/disabled amalagamation line macros
-########
-AMALGAMATION_LINE_MACROS=--linemacros=0
-if test "${amalgamation_line_macros}" = "yes" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=1
-fi
-if test "${amalgamation_line_macros}" = "no" ; then
- AMALGAMATION_LINE_MACROS=--linemacros=0
-fi
-AC_SUBST(AMALGAMATION_LINE_MACROS)
-
-#########
-# Output the config header
-AC_CONFIG_HEADERS(sqlite_cfg.h)
-
-#########
-# Generate the output files.
-#
-AC_SUBST(BUILD_CFLAGS)
-AC_CONFIG_FILES([
-Makefile
-sqlcipher.pc
-])
-AC_OUTPUT
diff --git a/doc/compile-for-unix.md b/doc/compile-for-unix.md
new file mode 100644
index 0000000000..ce76b97bae
--- /dev/null
+++ b/doc/compile-for-unix.md
@@ -0,0 +1,70 @@
+# Notes On Compiling SQLite On All Kinds Of Unix
+
+Here are step-by-step instructions on how to build SQLite from
+canonical source on any modern machine that isn't Windows. These
+notes are tested (on 2024-10-11) on Ubuntu and on MacOS, but they
+are general and should work on most any modern unix platform.
+See the companion document ([](./compile-for-windows.md>)) for
+guidance on building for Windows.
+
+ 1. Install a C-compiler. GCC or Clang both work fine. If you are
+ reading this document, you've probably already done that.
+
+ 2. *(Optional):* Install TCL development libraries. In this note,
+ we'll do a private install in the $HOME/local directory,
+ but you can make adjustments to install TCL wherever you like.
+ This document assumes you are working with TCL version 9.0.
+ See also the [](./tcl-extension-testing.md) document that contains
+ more details on compiling Tcl for use with SQLite.
+
+
Get the TCL source archive, perhaps from
+
+ or .
+
Untar the source archive. CD into the "unix/" subfolder
+ of the source tree.
+
Run: `mkdir $HOME/local`
+
Run: `./configure --prefix=$HOME/local`
+
Run: `make install`
+
+
+ As of 2024-10-25, TCL is not longer required for many
+ common build targets, such as "sqlite3.c" or the "sqlite3"
+ command-line tool. So you can skip this step if that is all
+ you want to build. TCL is still required to run "make test"
+ and similar, or to build the TCL extension, of course.
+
+ 4. Download the SQLite source tree and unpack it. CD into the
+ toplevel directory of the source tree.
+
+ 5. Run: `./configure --enable-all --with-tclsh=$HOME/local/bin/tclsh9.0`
+
+ You do not need to use --with-tclsh if the tclsh you want to use is the
+ first one on your PATH or if you are building without TCL.
+
+ 6. Run the "`Makefile`" makefile with an appropriate target.
+ Examples:
+
+
`make sqlite3.c`
+
`make sqlite3`
+
`make sqldiff`
+
`make sqlite3_rsync`
+
+
None of the targets above require TCL. TCL is needed
+ for the following targets:
+
+
`make tclextension-install`
+
`make devtest`
+
`make releasetest`
+
`make sqlite3_analyzer`
+
+
+ It is not required that you run the "tclextension-install" target prior to
+ running tests. However, the tests will run more smoothly if you do.
+ The version of SQLite used for the TCL extension does *not* need to
+ correspond to the version of SQLite under test. So you can install the
+ SQLite TCL extension once, and then use it to test many different versions
+ of SQLite.
+
+
+ 7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
+ commands work, add the the --with-debug argument to configure.
diff --git a/doc/compile-for-windows.md b/doc/compile-for-windows.md
index 20f79afa93..2e62286339 100644
--- a/doc/compile-for-windows.md
+++ b/doc/compile-for-windows.md
@@ -1,12 +1,23 @@
# Notes On Compiling SQLite On Windows 11
-Here are step-by-step instructions on how to build SQLite from
-canonical source on a new Windows 11 PC, as of 2023-08-16:
+Below are step-by-step instructions on how to build SQLite from
+canonical source on a new Windows 11 PC, as of 2024-10-09.
+See [](./compile-for-unix.md) for a similar guide for unix-like
+systems, including MacOS.
1. Install Microsoft Visual Studio. The free "community edition"
will work fine. Do a standard install for C++ development.
SQLite only needs the
"cl" compiler and the "nmake" build tool.
+
Note:
+ VS2015 or later is required for the procedures below to
+ all work. You *might* be able to get the build to work with
+ earlier versions of MSVC, but in that case the TCL installation
+ of step 3 will be required, since the "jimsh0.c" program of
+ Autosetup that is used as a substitute for "tclsh.exe" won't
+ compile with versions of Visual Studio prior to VS2015. In any
+ event, building SQLite from canonical source code on Windows
+ is not supported for earlier versions of Visual Studio.
2. Under the "Start" menu, find "All Apps" then go to "Visual Studio 20XX"
and find "x64 Native Tools Command Prompt for VS 20XX". Pin that
@@ -16,50 +27,83 @@ canonical source on a new Windows 11 PC, as of 2023-08-16:
a 32-bit build.) The subsequent steps will not work in a vanilla
DOS prompt. Nor will they work in PowerShell.
- 3. Install TCL development libraries. This note assumes that you will
+ 3. *(Optional):* Install TCL development libraries.
+ This note assumes that you will
install the TCL development libraries in the "`c:\Tcl`" directory.
Make adjustments
if you want TCL installed somewhere else. SQLite needs both the
- "tclsh.exe" command-line tool as part of the build process, and
- the "tcl86.lib" library in order to run tests. You will need
- TCL version 8.6 or later.
+ "tclsh90.exe" command-line tool as part of the build process, and
+ the "tcl90.lib" and "tclstub.lib" libraries in order to run tests.
+ This document assumes you are working with TCL version 9.0.
+ See [](./tcl-extension-testing.md#windows) for guidance on how
+ to compile TCL version 8.6 for use with SQLite.
Get the TCL source archive, perhaps from
- [https://www.tcl.tk/software/tcltk/download.html](https://www.tcl.tk/software/tcltk/download.html).
+
+ or .
Untar or unzip the source archive. CD into the "win/" subfolder
of the source tree.
-
CD to `c:\Tcl\lib`. In that subfolder make a copy of the
- "`tcl86t.lib`" file to the alternative name "`tcl86.lib`"
- (omitting the second 't'). Leave the copy in the same directory
- as the original.
-
CD to `c:\Tcl\bin`. Make a copy of the "`tclsh86t.exe`"
- file into "`tclsh.exe`" (without the "86t") in the same directory.
-
Add `c:\Tcl\bin` to your %PATH%. To do this, go to Settings
+
The previous two `nmake` commands must be run separately.
+
Also, the INSTALLDIR=... argument is required on both.
+
+
Optional: CD to `c:\Tcl\bin` and make a copy of
+ `tclsh90.exe` over into just `tclsh.exe`.
+
Optional:
+ Add `c:\Tcl\bin` to your %PATH%. To do this, go to Settings
and search for "path". Select "edit environment variables for
your account" and modify your default PATH accordingly.
You will need to close and reopen your command prompts after
making this change.
+ As of 2024-10-25, TCL is not longer required for many
+ common build targets, such as "sqlite3.c" or the "sqlite3.exe"
+ command-line tool. So you can skip this step if that is all
+ you want to build. TCL is still required to run "make test"
+ and similar, or to build the TCL extension, of course.
+
4. Download the SQLite source tree and unpack it. CD into the
toplevel directory of the source tree.
- 5. Set the TCLDIR environment variable to point to your TCL installation.
- Like this:
-
-
`set TCLDIR=c:\Tcl`
-
-
- 6. Run the "`Makefile.msc`" makefile with an appropriate target.
+ 5. Run the "`Makefile.msc`" makefile with an appropriate target.
Examples:
`nmake /f makefile.msc`
`nmake /f makefile.msc sqlite3.c`
+
`nmake /f makefile.msc sqlite3.exe`
+
`nmake /f makefile.msc sqldiff.exe`
+
`nmake /f makefile.msc sqlite3_rsync.exe`
+
+
No TCL is required for the nmake targets above. But for the ones
+ that follow, you will need a TCL installation, as described in step 3
+ above. If you install TCL in some directory other than C:\\Tcl, then
+ you will also need to add the "TCLDIR=<dir>" option on the
+ nmake command line to tell nmake where your TCL is installed.
+
+
`nmake /f makefile.msc tclextension-install`
`nmake /f makefile.msc devtest`
`nmake /f makefile.msc releasetest`
+
`nmake /f makefile.msc sqlite3_analyzer.exe`
+
+
+ It is not required that you run the "tclextension-install" target prior to
+ running tests. However, the tests will run more smoothly if you do.
+ The version of SQLite used for the TCL extension does *not* need to
+ correspond to the version of SQLite under test. So you can install the
+ SQLite TCL extension once, and then use it to test many different versions
+ of SQLite.
+
+
+ 7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
+ commands work, add the DEBUG=3 argument to nmake. Like this:
+
+
`nmake /f makefile.msc DEBUG=3 clean sqlite3.exe`
+
## 32-bit Builds
@@ -84,6 +128,18 @@ following minor changes:
`set PATH=c:\tcl32\bin;%PATH%`
+## Building a DLL
+
+The command the developers use for building the deliverable DLL on the
+[download page](https://sqlite.org/download.html) is as follows:
+
+> ~~~~
+nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
+~~~~
+
+That command generates both the sqlite3.dll and sqlite3.def files. The same
+command works for both 32-bit and 64-bit builds.
+
## Statically Linking The TCL Library
Some utility programs associated with SQLite need to be linked
@@ -96,7 +152,7 @@ nmake /f Makefile.msc sqlite3_analyzer.exe
~~~~
And you will end up with a working executable. However, that executable
-will depend on having the "tcl86.dll" library somewhere on your %PATH%.
+will depend on having the "tcl98.dll" library somewhere on your %PATH%.
Use the following steps to build an executable that has the TCL library
statically linked so that it does not depend on separate DLL:
@@ -106,27 +162,26 @@ statically linked so that it does not depend on separate DLL:
2. Untar the TCL source tarball into a fresh directory. CD into
the "win/" subfolder.
- 3. Run: `nmake /f makefile.vc OPTS=nothreads,static shell`
-
+ 3. Run: `nmake /f makefile.vc OPTS=static shell`
4. CD into the "Release*" subfolder that is created (note the
wildcard - the full name of the directory might vary). There
- you will find the "tcl86s.lib" file. Copy this file into the
- same directory that you put the "tcl86.lib" on your initial
+ you will find the "tcl90s.lib" file. Copy this file into the
+ same directory that you put the "tcl90.lib" on your initial
installation. (In this document, that directory is
"`C:\Tcl32\lib`" for 32-bit builds and
"`C:\Tcl\lib`" for 64-bit builds.)
5. CD into your SQLite source code directory and build the desired
- utility program, but add the following extra arguments to the
+ utility program, but add the following extra argument to the
nmake command line:
6. After your executable is built, you can verify that it does not
diff --git a/doc/jsonb.md b/doc/jsonb.md
new file mode 100644
index 0000000000..5beed1631d
--- /dev/null
+++ b/doc/jsonb.md
@@ -0,0 +1,290 @@
+# The JSONB Format
+
+This document describes SQLite's JSONB binary encoding of
+JSON.
+
+## 1.0 What Is JSONB?
+
+Beginning with version 3.45.0 (circa 2024-01-01), SQLite supports an
+alternative binary encoding of JSON which we call "JSONB". JSONB is
+a binary format that stored as a BLOB.
+
+The advantage of JSONB over ordinary text RFC 8259 JSON is that JSONB
+is both slightly smaller (by between 5% and 10% in most cases) and
+can be processed in less than half the number of CPU cycles. The built-in
+[JSON SQL functions] of SQLite can accept either ordinary text JSON
+or the binary JSONB encoding for any of their JSON inputs.
+
+The "JSONB" name is inspired by [PostgreSQL](https://postgresql.org), but the
+on-disk format for SQLite's JSONB is not the same as PostgreSQL's.
+The two formats have the same name, but they have wildly different internal
+representations and are not in any way binary compatible.
+
+The central idea behind this JSONB specification is that each element
+begins with a header that includes the size and type of that element.
+The header takes the place of punctuation such as double-quotes,
+curly-brackes, square-brackets, commas, and colons. Since the size
+and type of each element is contained in its header, the element can
+be read faster since it is no longer necessary to carefully scan forward
+looking for the closing delimiter. The payload of JSONB is the same
+as for corresponding text JSON. The same payload bytes occur in the
+same order. The only real difference between JSONB and ordinary text
+JSON is that JSONB includes a binary header on
+each element and omits delimiter and separator punctuation.
+
+### 1.1 Internal Use Only
+
+The details of the JSONB are not intended to be visible to application
+developers. Application developers should look at JSONB as an opaque BLOB
+used internally by SQLite. Nevertheless, we want the format to be backwards
+compatible across all future versions of SQLite. To that end, the format
+is documented by this file in the source tree. But this file should be
+used only by SQLite core developers, not by developers of applications
+that only use SQLite.
+
+## 2.0 The Purpose Of This Document
+
+JSONB is not intended as an external format to be used by
+applications. JSONB is designed for internal use by SQLite only.
+Programmers do not need to understand the JSONB format in order to
+use it effectively.
+Applications should access JSONB only through the [JSON SQL functions],
+not by looking at individual bytes of the BLOB.
+
+However, JSONB is intended to be portable and backwards compatible
+for all future versions of SQLite. In other words, you should not have
+to export and reimport your SQLite database files when you upgrade to
+a newer SQLite version. For that reason, the JSONB format needs to
+be well-defined.
+
+This document is therefore similar in purpose to the
+[SQLite database file format] document that describes the on-disk
+format of an SQLite database file. Applications are not expected
+to directly read and write the bits and bytes of SQLite database files.
+The SQLite database file format is carefully documented so that it
+can be stable and enduring. In the same way, the JSONB representation
+of JSON is documented here so that it too can be stable and enduring,
+not so that applications can read or writes individual bytes.
+
+## 3.0 Encoding
+
+JSONB is a direct translation of the underlying text JSON. The difference
+is that JSONB uses a binary encoding that is faster to parse compared to
+the detailed syntax of text JSON.
+
+Each JSON element is encoded as a header and a payload. The header
+determines type of element (string, numeric, boolean, null, object, or
+array) and the size of the payload. The header can be between 1 and
+9 bytes in size. The payload can be any size from zero bytes up to the
+maximum allowed BLOB size.
+
+### 3.1 Payload Size
+
+The upper four bits of the first byte of the header determine size of the
+header and possibly also the size of the payload.
+If the upper four bits have a value between 0 and 11, then the header is
+exactly one byte in size and the payload size is determined by those
+upper four bits. If the upper four bits have a value between 12 and 15,
+that means that the total header size is 2, 3, 5, or 9 bytes and the
+payload size is unsigned big-endian integer that is contained in the
+subsequent bytes. The size integer is the one byte that following the
+initial header byte if the upper four bits
+are 12, two bytes if the upper bits are 13, four bytes if the upper bits
+are 14, and eight bytes if the upper bits are 15. The current design
+of SQLite does not support BLOB values larger than 2GiB, so the eight-byte
+variant of the payload size integer will never be used by the current code.
+The eight-byte payload size integer is included in the specification
+to allow for future expansion.
+
+The header for an element does *not* need to be in its simplest
+form. For example, consider the JSON numeric value "`1`".
+That element can be encode in five different ways:
+
+ * `0x13 0x31`
+ * `0xc3 0x01 0x31`
+ * `0xd3 0x00 0x01 0x31`
+ * `0xe3 0x00 0x00 0x00 0x01 0x31`
+ * `0xf3 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x31`
+
+The shortest encoding is preferred, of course, and usually happens with
+primitive elements such as numbers. However the total size of an array
+or object might not be known exactly when the header of the element is
+first generated. It is convenient to reserve space for the largest
+possible header and then go back and fill in the correct payload size
+at the end. This technique can result in array or object headers that
+are larger than absolutely necessary.
+
+### 3.2 Element Type
+
+The least-significant four bits of the first byte of the header (the first
+byte masked against 0x0f) determine element type. The following codes are
+used:
+
+
+
NULL →
+The element is a JSON "null". The payload size for a true JSON NULL must
+must be zero. Future versions of SQLite might extend the JSONB format
+with elements that have a zero element type but a non-zero size. In that
+way, legacy versions of SQLite will interpret the element as a NULL
+for backwards compatibility while newer versions will interpret the
+element in some other way.
+
+
TRUE →
+The element is a JSON "true". The payload size must be zero for a actual
+"true" value. Elements with type 1 and a non-zero payload size are
+reserved for future expansion. Legacy implementations that see an element
+type of 1 with a non-zero payload size should continue to interpret that
+element as "true" for compatibility.
+
+
FALSE →
+The element is a JSON "false". The payload size must be zero for a actual
+"false" value. Elements with type 2 and a non-zero payload size are
+reserved for future expansion. Legacy implementations that see an element
+type of 2 with a non-zero payload size should continue to interpret that
+element as "false" for compatibility.
+
+
INT →
+The element is a JSON integer value in the canonical
+RFC 8259 format, without extensions. The payload is the ASCII
+text representation of that numeric value.
+
+
INT5 →
+The element is a JSON integer value that is not in the
+canonical format. The payload is the ASCII
+text representation of that numeric value. Because the payload is in a
+non-standard format, it will need to be translated when the JSONB is
+converted into RFC 8259 text JSON.
+
+
FLOAT →
+The element is a JSON floating-point value in the canonical
+RFC 8259 format, without extensions. The payload is the ASCII
+text representation of that numeric value.
+
+
FLOAT5 →
+The element is a JSON floating-point value that is not in the
+canonical format. The payload is the ASCII
+text representation of that numeric value. Because the payload is in a
+non-standard format, it will need to be translated when the JSONB is
+converted into RFC 8259 text JSON.
+
+
TEXT →
+The element is a JSON string value that does not contain
+any escapes nor any characters that need to be escaped for either SQL or
+JSON. The payload is the UTF8 text representation of the string value.
+The payload does not include string delimiters.
+
+
TEXTJ →
+The element is a JSON string value that contains
+RFC 8259 character escapes (such as "\n" or "\u0020").
+Those escapes will need to be translated into actual UTF8 if this element
+is [json_extract|extracted] into SQL.
+The payload is the UTF8 text representation of the escaped string value.
+The payload does not include string delimiters.
+
+
TEXT5 →
+The element is a JSON string value that contains
+character escapes, including some character escapes that part of JSON5
+and which are not found in the canonical RFC 8259 spec.
+Those escapes will need to be translated into standard JSON prior to
+rendering the JSON as text, or into their actual UTF8 characters if this
+element is [json_extract|extracted] into SQL.
+The payload is the UTF8 text representation of the escaped string value.
+The payload does not include string delimiters.
+
+
TEXTRAW →
+The element is a JSON string value that contains
+UTF8 characters that need to be escaped if this string is rendered into
+standard JSON text.
+The payload does not include string delimiters.
+
+
ARRAY →
+The element is a JSON array. The payload contains
+JSONB elements that comprise values contained within the array.
+
+
OBJECT →
+The element is a JSON object. The payload contains
+pairs of JSONB elements that comprise entries for the JSON object.
+The first element in each pair must be a string (types 7 through 10).
+The second element of each pair may be any types, including nested
+arrays or objects.
+
+
RESERVED-13 →
+Reserved for future expansion. Legacy implements that encounter this
+element type should raise an error.
+
+
RESERVED-14 →
+Reserved for future expansion. Legacy implements that encounter this
+element type should raise an error.
+
+
RESERVED-15 →
+Reserved for future expansion. Legacy implements that encounter this
+element type should raise an error.
+
+
+Element types outside the range of 0 to 12 are reserved for future
+expansion. The current implement raises an error if see an element type
+other than those listed above. However, future versions of SQLite might
+use of the three remaining element types to implement indexing or similar
+optimizations, to speed up lookup against large JSON arrays and/or objects.
+
+### 3.3 Design Rationale For Element Types
+
+A key goal of JSONB is that it should be quick to translate
+to and from text JSON and/or be constructed from SQL values.
+When converting from text into JSONB, we do not want the
+converter subroutine to burn CPU cycles converting elements
+values into some standard format which might never be used.
+Format conversion is "lazy" - it is deferred until actually
+needed. This has implications for the JSONB format design:
+
+ 1. Numeric values are stored as text, not a numbers. The values are
+ a direct copy of the text JSON values from which they are derived.
+
+ 2. There are multiple element types depending on the details of value
+ formats. For example, INT is used for pure RFC-8259 integer
+ literals and INT5 exists for JSON5 extensions such as hexadecimal
+ notation. FLOAT is used for pure RFC-8259 floating point literals
+ and FLOAT5 is used for JSON5 extensions. There are four different
+ representations of strings, depending on where the string came from
+ and how special characters within the string are escaped.
+
+A second goal of JSONB is that it should be capable of serving as the
+"parse tree" for JSON when a JSON value is being processed by the
+various [JSON SQL functions] built into SQLite. Before JSONB was
+developed, operations such [json_replace()] and [json_patch()]
+and similar worked in three stages:
+
+
+ 1. Translate the text JSON into a internal format that is
+ easier to scan and edit.
+ 2. Perform the requested operation on the JSON.
+ 3. Translate the internal format back into text.
+
+JSONB seeks to serve as the internal format directly - bypassing
+the first and third stages of that process. Since most of the CPU
+cycles are spent on the first and third stages, that suggests that
+JSONB processing will be much faster than text JSON processing.
+
+So when processing JSONB, only the second stage of the three-stage
+process is required. But when processing text JSON, it is still necessary
+to do stages one and three. If JSONB is to be used as the internal
+binary representation, this is yet another reason to store numeric
+values as text. Storing numbers as text minimizes the amount of
+conversion work needed for stages one and three. This is also why
+there are four different representations of text in JSONB. Different
+text representations are used for text coming from different sources
+(RFC-8259 JSON, JSON5, or SQL string values) and conversions only
+happen if and when they are actually needed.
+
+### 3.4 Valid JSONB BLOBs
+
+A valid JSONB BLOB consists of a single JSON element. The element must
+exactly fill the BLOB. This one element is often a JSON object or array
+and those usually contain additional elements as its payload, but the
+element can be a primite value such a string, number, boolean, or null.
+
+When the built-in JSON functions are attempting to determine if a BLOB
+argument is a JSONB or just a random BLOB, they look at the header of
+the outer element to see that it is well-formed and that the element
+completely fills the BLOB. If these conditions are met, then the BLOB
+is accepted as a JSONB value.
diff --git a/doc/lemon.html b/doc/lemon.html
index 66665f46f3..4147d9b31e 100644
--- a/doc/lemon.html
+++ b/doc/lemon.html
@@ -683,6 +683,7 @@
the wildcard token and some other token, the other token is always used.
The wildcard token is only matched if there are no alternatives.
+
+
4.4.26 The %realloc and %free directives
+
+
The %realloc and %free directives defines function
+that allocate and free heap memory. The signatures of these functions
+should be the same as the realloc() and free() functions from the standard
+C library.
+
+
If both of these functions are defined
+then these functions are used to allocate and free
+memory for supplemental parser stack space, if the initial
+parse stack space is exceeded. The initial parser stack size
+is specified by either %stack_size or the
+-DYYSTACKDEPTH compile-time flag.
+
5.0 Error Processing
@@ -1224,6 +1241,7 @@
5.0 Error Processing
first syntax error, of course, if there are no instances of the
"error" non-terminal in your grammar.
+
6.0 History of Lemon
diff --git a/doc/tcl-extension-testing.md b/doc/tcl-extension-testing.md
new file mode 100644
index 0000000000..df5f6537ba
--- /dev/null
+++ b/doc/tcl-extension-testing.md
@@ -0,0 +1,208 @@
+# Test Procedures For The SQLite TCL Extension
+
+## 1.0 Background
+
+The SQLite TCL extension logic (in the
+"[tclsqlite.c](/file/src/tclsqlite.c)" source
+file) is statically linked into "textfixture" executable
+which is the program used to do most of the testing
+associated with "make test", "make devtest", and/or
+"make releasetest". So the functionality of the SQLite
+TCL extension is thoroughly vetted during normal testing. The
+procedures below are designed to test the loadable extension
+aspect of the SQLite TCL extension, and in particular to verify
+that the "make tclextension-install" build target works and that
+an ordinary tclsh can subsequently run "package require sqlite3".
+
+This procedure can also be used as a template for how to set up
+a local TCL+SQLite development environment. In other words, it
+can be be used as a guide on how to compile per-user copies of
+Tcl that are used to develop, test, and debug SQLite. In that
+case, perhaps make minor changes to the procedure such as:
+
+ * Make TCLBUILD directory is permanent.
+ * Enable debugging symbols on the Tcl library build.
+ * Reduce the optimization level to -O0 for easier debugging.
+ * Also compile "wish" to go with each "tclsh".
+
+
+
+## 2.0 Testing On Unix-like Systems (Including Mac)
+
+See also the [](./compile-for-unix.md) document which provides another
+perspective on how to compile SQLite on unix-like systems.
+
+### 2.1 Setup
+
+
+
+ [Fossil](https://fossil-scm.org/) installed.
+
Check out source code and set environment variables:
+
+
**TCLSOURCE** →
+ The top-level directory of a Fossil check-out of the TCL source tree.
+
**SQLITESOURCE** →
+ A Fossil check-out of the SQLite source tree.
+
**TCLBUILD** →
+ A directory that does not exist at the start of the test and which
+ will be deleted at the end of the test, and that will contain the
+ test builds of the TCL libraries and the SQLite TCL Extensions.
+
+
+
+### 2.2 Testing TCL 8.6 on unix
+
+
+
`mkdir -p $TCLBUILD/tcl86`
+
`cd $TCLSOURCE/unix`
+
`fossil up core-8-6-16`
+ ↑ Or some other version of Tcl8.6.
+
`fossil clean -x`
+
`./configure --prefix=$TCLBUILD/tcl86 --disable-shared`
+ ↑ The --disable-shared is to avoid the need to set LD_LIBRARY_PATH
+ when using this Tcl build.
+
`make tclextension-verify`
+ ↑ Verify that the correct version is installed.
+
`$TCLBUILD/tcl86/bin/tclsh8.6 test/testrunner.tcl release --explain`
+ ↑ Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+
+
+### 2.3 Testing TCL 9.0 on unix
+
+
+
`mkdir -p $TCLBUILD/tcl90`
+
`fossil up core-9-0-0`
+ ↑ Or some other version of Tcl9
+
`fossil clean -x`
+
`./configure --prefix=$TCLBUILD/tcl90 --disable-shared`
+ ↑ The --disable-shared is to avoid the need to set LD_LIBRARY_PATH
+ when using this Tcl build.
+
`make install`
+
`cp -r ../library $TCLBUILD/tcl90/lib/tcl9.0`
+ ↑ The Tcl library is not installed by "make install" for Tcl9.0 unless
+ you also include the --disable-zipfs to ./configure. But if you do that
+ then the generated tclsh9.0 is no longer stand-alone. On the other hand,
+ if you don't install the Tcl library, other programs like testfixture
+ won't be able to find the Tcl library and hence won't work. This
+ extra installation step resolves the dilemma.
+ This step is not required when building Tcl8.6, which lacks support for
+ zipfs and hence always installs its Tcl library.
+
`$TCLBUILD/tcl90/bin/tclsh9.0 test/testrunner.tcl release --explain`
+ ↑ Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+
+
+### 2.4 Cleanup
+
+
+
`rm -rf $TCLBUILD`
+
+
+
+## 3.0 Testing On Windows
+
+See also the [](./compile-for-windows.md) document which provides another
+perspective on how to compile SQLite on Windows.
+
+### 3.1 Setup for Windows
+
+
+
[Visual Studio](https://visualstudio.microsoft.com/vs/community/)
+ installed. VS2015 or later required.
+
Check out source code and set environment variables.
+
+
**TCLSOURCE** →
+ The top-level directory of a Fossil check-out of the TCL source tree.
+
**SQLITESOURCE** →
+ A Fossil check-out of the SQLite source tree.
+
**TCLBUILD** →
+ A directory that does not exist at the start of the test and which
+ will be deleted at the end of the test, and that will contain the
+ test builds of the TCL libraries and the SQLite TCL Extensions.
+
**ORIGINALPATH** →
+ The original value of %PATH%. In other words, set as follows:
+ `set ORIGINALPATH %PATH%`
+
+
+
+### 3.2 Testing TCL 8.6 on Windows
+
+
+
`mkdir %TCLBUILD%\tcl86`
+
`cd %TCLSOURCE%\win`
+
`fossil up core-8-6-16`
+ ↑ Or some other version of Tcl8.6.
+
`fossil clean -x`
+
`set INSTALLDIR=%TCLBUILD%\tcl86`
+
`nmake /f makefile.vc release`
+ ⇅ You *must* invoke the "release" and "install" targets
+ using separate "nmake" commands or tclsh86t.exe won't be
+ installed.
+
`tclsh86t test/testrunner.tcl release --explain`
+ ↑ Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+
+
+### 3.3 Testing TCL 9.0 on Windows
+
+
+
`mkdir %TCLBUILD%\tcl90`
+
`cd %TCLSOURCE%\win`
+
`fossil up core-9-0-0`
+ ↑ Or some other version of Tcl9
+
`fossil clean -x`
+
`set INSTALLDIR=%TCLBUILD%\tcl90`
+
`nmake /f makefile.vc release`
+ ⇅ You *must* invoke the "release" and "install" targets
+ using separate "nmake" commands or tclsh90.exe won't be
+ installed.
+
`tclsh90 test/testrunner.tcl release --explain`
+ ↑ Verify thousands of lines of output with no errors. Or
+ consider running "devtest" without --explain instead of "release".
+
+
+### 3.4 Cleanup
+
+
+
`rm -rf %TCLBUILD%`
+
diff --git a/doc/testrunner.md b/doc/testrunner.md
index d828fd76d8..d0248573ee 100644
--- a/doc/testrunner.md
+++ b/doc/testrunner.md
@@ -2,6 +2,25 @@
# The testrunner.tcl Script
+
+
+
# 1. Overview
testrunner.tcl is a Tcl script used to run multiple SQLite tests using
@@ -9,12 +28,18 @@ multiple jobs. It supports the following types of tests:
* Tcl test scripts.
- * Tests run with [make] commands. Specifically, at time of writing,
- [make fuzztest], [make mptest], [make sourcetest] and [make threadtest].
+ * Tests run with `make` commands. Examples:
+ - `make mdevtest`
+ - `make releasetest`
+ - `make sdevtest`
+ - `make testrunner`
testrunner.tcl pipes the output of all tests and builds run into log file
-**testrunner.log**, created in the cwd directory. Searching this file for
-"failed" is a good way to find the output of a failed test.
+**testrunner.log**, created in the current working directory. Search this
+file to find details of errors. Suggested search commands:
+
+ * `grep "^!" testrunner.log`
+ * `grep failed testrunner.log`
testrunner.tcl also populates SQLite database **testrunner.db**. This database
contains details of all tests run, running and to be run. A useful query
@@ -40,16 +65,17 @@ Running:
in another terminal is a good way to keep an eye on a long running test.
-Sometimes testrunner.tcl uses the [testfixture] binary that it is run with
+Sometimes testrunner.tcl uses the `testfixture` binary that it is run with
to run tests (see "Binary Tests" below). Sometimes it builds testfixture and
other binaries in specific configurations to test (see "Source Tests").
+
# 2. Binary Tests
The commands described in this section all run various combinations of the Tcl
-test scripts using the [testfixture] binary used to run the testrunner.tcl
+test scripts using the `testfixture` binary used to run the testrunner.tcl
script (i.e. they do not invoke the compiler to build new binaries, or the
-[make] command to run tests that are not Tcl scripts). The procedure to run
+`make` command to run tests that are not Tcl scripts). The procedure to run
these tests is therefore:
1. Build the "testfixture" (or "testfixture.exe" for windows) binary using
@@ -61,6 +87,7 @@ these tests is therefore:
The following sub-sections describe the various options that can be
passed to testrunner.tcl to test binary testfixture builds.
+
## 2.1. Organization of Tcl Tests
Tcl tests are stored in files that match the pattern *\*.test*. They are
@@ -91,6 +118,7 @@ Running **all** tests is to run all tests in the full test set, plus a dozen
or so permutations. The specific permutations that are run as part of "all"
are defined in file *testrunner_data.tcl*.
+
## 2.2. Commands to Run Tests
To run the "veryquick" test set, use either of the following:
@@ -114,6 +142,12 @@ a specified pattern (e.g. all tests that start with "fts5"), either of:
./testfixture $TESTDIR/testrunner.tcl 'fts5*'
```
+Strictly speaking, for a test to be run the pattern must match the script
+filename, not including the directory, using the rules of Tcl's
+\[string match\] command. Except that before the matching is done, any "%"
+characters specified as part of the pattern are transformed to "\*".
+
+
To run "all" tests (full + permutations):
```
@@ -141,6 +175,7 @@ Or, if the failure occured as part of a permutation:
TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?
+
# 3. Source Code Tests
The commands described in this section invoke the C compiler to build
@@ -159,10 +194,11 @@ shell that supports SQLite 3.31.1 or newer via "package require sqlite3".
TODO: ./configure + Makefile.msc build systems.
-## Commands to Run SQLite Tests
+
+## 3.1. Commands to Run SQLite Tests
The **mdevtest** command is equivalent to running the veryquick tests and
-the [make fuzztest] target once for each of two --enable-all builds - one
+the `make fuzztest` target once for each of two --enable-all builds - one
with debugging enabled and one without:
```
@@ -201,7 +237,18 @@ of the specific tests run.
tclsh $TESTDIR/testrunner.tcl release
```
-## Running ZipVFS Tests
+As with source code tests, one or more patterns
+may be appended to any of the above commands (mdevtest, sdevtest or release).
+In that case only Tcl tests (no fuzz or other tests) that match the specified
+pattern are run. For example, to run the just the Tcl rtree tests in all
+builds and configurations supported by "release":
+
+```
+ tclsh $TESTDIR/testrunner.tcl release rtree%
+```
+
+
+## 3.2. Running ZipVFS Tests
testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
tests from the Zipvfs project with the following command:
@@ -217,7 +264,8 @@ test both SQLite and Zipvfs with a single command:
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
```
-## Investigating Source Code Test Failures
+
+## 3.3. Investigating Source Code Test Failures
Investigating a test failure that occurs during source code testing is a
two step process:
@@ -240,13 +288,45 @@ a dos \*.bat file on windows. For example:
```
The generated bash or \*.bat file script accepts a single argument - a makefile
-target to build. This may be used either to run a [make] command test directly,
+target to build. This may be used either to run a `make` command test directly,
or else to build a testfixture (or testfixture.exe) binary with which to
run a Tcl test script, as described above.
+
+# 4. Extra testrunner.tcl Options
+The testrunner.tcl script options in this section may be used with both source
+code and binary tests.
-# 4. Controlling CPU Core Utilization
+The **--buildonly** option instructs testrunner.tcl just to build the binaries
+required by a test, not to run any actual tests. For example:
+
+```
+ # Build binaries required by release test.
+ tclsh $TESTDIR/testrunner.tcl --buildonly release"
+```
+
+The **--dryrun** option prevents testrunner.tcl from building any binaries
+or running any tests. Instead, it just writes the shell commands that it
+would normally execute into the testrunner.log file. Example:
+
+```
+ # Log the shell commmands that make up the mdevtest test.
+ tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
+```
+
+The **--explain** option is similar to --dryrun in that it prevents testrunner.tcl
+from building any binaries or running any tests. The difference is that --explain
+prints on standard output a human-readable summary of all the builds and tests that
+would have been run.
+
+```
+ # Show what builds and tests would have been run
+ tclsh $TESTDIR/testrunner.tcl --explain mdevtest
+```
+
+
+# 5. Controlling CPU Core Utilization
When running either binary or source code tests, testrunner.tcl reports the
number of jobs it intends to use to stdout. e.g.
@@ -274,11 +354,3 @@ testrunner.log and testrunner.db files:
```
$ ./testfixture $TESTDIR/testrunner.tcl njob $NEW_NUMBER_OF_JOBS
```
-
-
-
-
-
-
-
-
diff --git a/ext/async/README.txt b/ext/async/README.txt
deleted file mode 100644
index f62fa2fc17..0000000000
--- a/ext/async/README.txt
+++ /dev/null
@@ -1,170 +0,0 @@
-NOTE (2012-11-29):
-
-The functionality implemented by this extension has been superseded
-by WAL-mode. This module is no longer supported or maintained. The
-code is retained for historical reference only.
-
-------------------------------------------------------------------------------
-
-Normally, when SQLite writes to a database file, it waits until the write
-operation is finished before returning control to the calling application.
-Since writing to the file-system is usually very slow compared with CPU
-bound operations, this can be a performance bottleneck. This directory
-contains an extension that causes SQLite to perform all write requests
-using a separate thread running in the background. Although this does not
-reduce the overall system resources (CPU, disk bandwidth etc.) at all, it
-allows SQLite to return control to the caller quickly even when writing to
-the database, eliminating the bottleneck.
-
- 1. Functionality
-
- 1.1 How it Works
- 1.2 Limitations
- 1.3 Locking and Concurrency
-
- 2. Compilation and Usage
-
- 3. Porting
-
-
-
-1. FUNCTIONALITY
-
- With asynchronous I/O, write requests are handled by a separate thread
- running in the background. This means that the thread that initiates
- a database write does not have to wait for (sometimes slow) disk I/O
- to occur. The write seems to happen very quickly, though in reality
- it is happening at its usual slow pace in the background.
-
- Asynchronous I/O appears to give better responsiveness, but at a price.
- You lose the Durable property. With the default I/O backend of SQLite,
- once a write completes, you know that the information you wrote is
- safely on disk. With the asynchronous I/O, this is not the case. If
- your program crashes or if a power loss occurs after the database
- write but before the asynchronous write thread has completed, then the
- database change might never make it to disk and the next user of the
- database might not see your change.
-
- You lose Durability with asynchronous I/O, but you still retain the
- other parts of ACID: Atomic, Consistent, and Isolated. Many
- appliations get along fine without the Durablity.
-
- 1.1 How it Works
-
- Asynchronous I/O works by creating a special SQLite "vfs" structure
- and registering it with sqlite3_vfs_register(). When files opened via
- this vfs are written to (using the vfs xWrite() method), the data is not
- written directly to disk, but is placed in the "write-queue" to be
- handled by the background thread.
-
- When files opened with the asynchronous vfs are read from
- (using the vfs xRead() method), the data is read from the file on
- disk and the write-queue, so that from the point of view of
- the vfs reader the xWrite() appears to have already completed.
-
- The special vfs is registered (and unregistered) by calls to the
- API functions sqlite3async_initialize() and sqlite3async_shutdown().
- See section "Compilation and Usage" below for details.
-
- 1.2 Limitations
-
- In order to gain experience with the main ideas surrounding asynchronous
- IO, this implementation is deliberately kept simple. Additional
- capabilities may be added in the future.
-
- For example, as currently implemented, if writes are happening at a
- steady stream that exceeds the I/O capability of the background writer
- thread, the queue of pending write operations will grow without bound.
- If this goes on for long enough, the host system could run out of memory.
- A more sophisticated module could to keep track of the quantity of
- pending writes and stop accepting new write requests when the queue of
- pending writes grows too large.
-
- 1.3 Locking and Concurrency
-
- Multiple connections from within a single process that use this
- implementation of asynchronous IO may access a single database
- file concurrently. From the point of view of the user, if all
- connections are from within a single process, there is no difference
- between the concurrency offered by "normal" SQLite and SQLite
- using the asynchronous backend.
-
- If file-locking is enabled (it is enabled by default), then connections
- from multiple processes may also read and write the database file.
- However concurrency is reduced as follows:
-
- * When a connection using asynchronous IO begins a database
- transaction, the database is locked immediately. However the
- lock is not released until after all relevant operations
- in the write-queue have been flushed to disk. This means
- (for example) that the database may remain locked for some
- time after a "COMMIT" or "ROLLBACK" is issued.
-
- * If an application using asynchronous IO executes transactions
- in quick succession, other database users may be effectively
- locked out of the database. This is because when a BEGIN
- is executed, a database lock is established immediately. But
- when the corresponding COMMIT or ROLLBACK occurs, the lock
- is not released until the relevant part of the write-queue
- has been flushed through. As a result, if a COMMIT is followed
- by a BEGIN before the write-queue is flushed through, the database
- is never unlocked,preventing other processes from accessing
- the database.
-
- File-locking may be disabled at runtime using the sqlite3async_control()
- API (see below). This may improve performance when an NFS or other
- network file-system, as the synchronous round-trips to the server be
- required to establish file locks are avoided. However, if multiple
- connections attempt to access the same database file when file-locking
- is disabled, application crashes and database corruption is a likely
- outcome.
-
-
-2. COMPILATION AND USAGE
-
- The asynchronous IO extension consists of a single file of C code
- (sqlite3async.c), and a header file (sqlite3async.h) that defines the
- C API used by applications to activate and control the modules
- functionality.
-
- To use the asynchronous IO extension, compile sqlite3async.c as
- part of the application that uses SQLite. Then use the API defined
- in sqlite3async.h to initialize and configure the module.
-
- The asynchronous IO VFS API is described in detail in comments in
- sqlite3async.h. Using the API usually consists of the following steps:
-
- 1. Register the asynchronous IO VFS with SQLite by calling the
- sqlite3async_initialize() function.
-
- 2. Create a background thread to perform write operations and call
- sqlite3async_run().
-
- 3. Use the normal SQLite API to read and write to databases via
- the asynchronous IO VFS.
-
- Refer to sqlite3async.h for details.
-
-
-3. PORTING
-
- Currently the asynchronous IO extension is compatible with win32 systems
- and systems that support the pthreads interface, including Mac OSX, Linux,
- and other varieties of Unix.
-
- To port the asynchronous IO extension to another platform, the user must
- implement mutex and condition variable primitives for the new platform.
- Currently there is no externally available interface to allow this, but
- modifying the code within sqlite3async.c to include the new platforms
- concurrency primitives is relatively easy. Search within sqlite3async.c
- for the comment string "PORTING FUNCTIONS" for details. Then implement
- new versions of each of the following:
-
- static void async_mutex_enter(int eMutex);
- static void async_mutex_leave(int eMutex);
- static void async_cond_wait(int eCond, int eMutex);
- static void async_cond_signal(int eCond);
- static void async_sched_yield(void);
-
- The functionality required of each of the above functions is described
- in comments in sqlite3async.c.
diff --git a/ext/async/sqlite3async.c b/ext/async/sqlite3async.c
deleted file mode 100644
index eed7c8d738..0000000000
--- a/ext/async/sqlite3async.c
+++ /dev/null
@@ -1,1706 +0,0 @@
-/*
-** 2005 December 14
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-**
-** $Id: sqlite3async.c,v 1.7 2009/07/18 11:52:04 danielk1977 Exp $
-**
-** This file contains the implementation of an asynchronous IO backend
-** for SQLite.
-*/
-
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO)
-
-#include "sqlite3async.h"
-#include "sqlite3.h"
-#include
-#include
-#include
-
-/* Useful macros used in several places */
-#define MIN(x,y) ((x)<(y)?(x):(y))
-#define MAX(x,y) ((x)>(y)?(x):(y))
-
-#ifndef SQLITE_AMALGAMATION
-/* Macro to mark parameters as unused and silence compiler warnings. */
-#define UNUSED_PARAMETER(x) (void)(x)
-#endif
-
-/* Forward references */
-typedef struct AsyncWrite AsyncWrite;
-typedef struct AsyncFile AsyncFile;
-typedef struct AsyncFileData AsyncFileData;
-typedef struct AsyncFileLock AsyncFileLock;
-typedef struct AsyncLock AsyncLock;
-
-/* Enable for debugging */
-#ifndef NDEBUG
-#include
-static int sqlite3async_trace = 0;
-# define ASYNC_TRACE(X) if( sqlite3async_trace ) asyncTrace X
-static void asyncTrace(const char *zFormat, ...){
- char *z;
- va_list ap;
- va_start(ap, zFormat);
- z = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
- fprintf(stderr, "[%d] %s", 0 /* (int)pthread_self() */, z);
- sqlite3_free(z);
-}
-#else
-# define ASYNC_TRACE(X)
-#endif
-
-/*
-** THREAD SAFETY NOTES
-**
-** Basic rules:
-**
-** * Both read and write access to the global write-op queue must be
-** protected by the async.queueMutex. As are the async.ioError and
-** async.nFile variables.
-**
-** * The async.pLock list and all AsyncLock and AsyncFileLock
-** structures must be protected by the async.lockMutex mutex.
-**
-** * The file handles from the underlying system are not assumed to
-** be thread safe.
-**
-** * See the last two paragraphs under "The Writer Thread" for
-** an assumption to do with file-handle synchronization by the Os.
-**
-** Deadlock prevention:
-**
-** There are three mutex used by the system: the "writer" mutex,
-** the "queue" mutex and the "lock" mutex. Rules are:
-**
-** * It is illegal to block on the writer mutex when any other mutex
-** are held, and
-**
-** * It is illegal to block on the queue mutex when the lock mutex
-** is held.
-**
-** i.e. mutex's must be grabbed in the order "writer", "queue", "lock".
-**
-** File system operations (invoked by SQLite thread):
-**
-** xOpen
-** xDelete
-** xFileExists
-**
-** File handle operations (invoked by SQLite thread):
-**
-** asyncWrite, asyncClose, asyncTruncate, asyncSync
-**
-** The operations above add an entry to the global write-op list. They
-** prepare the entry, acquire the async.queueMutex momentarily while
-** list pointers are manipulated to insert the new entry, then release
-** the mutex and signal the writer thread to wake up in case it happens
-** to be asleep.
-**
-**
-** asyncRead, asyncFileSize.
-**
-** Read operations. Both of these read from both the underlying file
-** first then adjust their result based on pending writes in the
-** write-op queue. So async.queueMutex is held for the duration
-** of these operations to prevent other threads from changing the
-** queue in mid operation.
-**
-**
-** asyncLock, asyncUnlock, asyncCheckReservedLock
-**
-** These primitives implement in-process locking using a hash table
-** on the file name. Files are locked correctly for connections coming
-** from the same process. But other processes cannot see these locks
-** and will therefore not honor them.
-**
-**
-** The writer thread:
-**
-** The async.writerMutex is used to make sure only there is only
-** a single writer thread running at a time.
-**
-** Inside the writer thread is a loop that works like this:
-**
-** WHILE (write-op list is not empty)
-** Do IO operation at head of write-op list
-** Remove entry from head of write-op list
-** END WHILE
-**
-** The async.queueMutex is always held during the test, and when the entry is removed from the head
-** of the write-op list. Sometimes it is held for the interim
-** period (while the IO is performed), and sometimes it is
-** relinquished. It is relinquished if (a) the IO op is an
-** ASYNC_CLOSE or (b) when the file handle was opened, two of
-** the underlying systems handles were opened on the same
-** file-system entry.
-**
-** If condition (b) above is true, then one file-handle
-** (AsyncFile.pBaseRead) is used exclusively by sqlite threads to read the
-** file, the other (AsyncFile.pBaseWrite) by sqlite3_async_flush()
-** threads to perform write() operations. This means that read
-** operations are not blocked by asynchronous writes (although
-** asynchronous writes may still be blocked by reads).
-**
-** This assumes that the OS keeps two handles open on the same file
-** properly in sync. That is, any read operation that starts after a
-** write operation on the same file system entry has completed returns
-** data consistent with the write. We also assume that if one thread
-** reads a file while another is writing it all bytes other than the
-** ones actually being written contain valid data.
-**
-** If the above assumptions are not true, set the preprocessor symbol
-** SQLITE_ASYNC_TWO_FILEHANDLES to 0.
-*/
-
-
-#ifndef NDEBUG
-# define TESTONLY( X ) X
-#else
-# define TESTONLY( X )
-#endif
-
-/*
-** PORTING FUNCTIONS
-**
-** There are two definitions of the following functions. One for pthreads
-** compatible systems and one for Win32. These functions isolate the OS
-** specific code required by each platform.
-**
-** The system uses three mutexes and a single condition variable. To
-** block on a mutex, async_mutex_enter() is called. The parameter passed
-** to async_mutex_enter(), which must be one of ASYNC_MUTEX_LOCK,
-** ASYNC_MUTEX_QUEUE or ASYNC_MUTEX_WRITER, identifies which of the three
-** mutexes to lock. Similarly, to unlock a mutex, async_mutex_leave() is
-** called with a parameter identifying the mutex being unlocked. Mutexes
-** are not recursive - it is an error to call async_mutex_enter() to
-** lock a mutex that is already locked, or to call async_mutex_leave()
-** to unlock a mutex that is not currently locked.
-**
-** The async_cond_wait() and async_cond_signal() functions are modelled
-** on the pthreads functions with similar names. The first parameter to
-** both functions is always ASYNC_COND_QUEUE. When async_cond_wait()
-** is called the mutex identified by the second parameter must be held.
-** The mutex is unlocked, and the calling thread simultaneously begins
-** waiting for the condition variable to be signalled by another thread.
-** After another thread signals the condition variable, the calling
-** thread stops waiting, locks mutex eMutex and returns. The
-** async_cond_signal() function is used to signal the condition variable.
-** It is assumed that the mutex used by the thread calling async_cond_wait()
-** is held by the caller of async_cond_signal() (otherwise there would be
-** a race condition).
-**
-** It is guaranteed that no other thread will call async_cond_wait() when
-** there is already a thread waiting on the condition variable.
-**
-** The async_sched_yield() function is called to suggest to the operating
-** system that it would be a good time to shift the current thread off the
-** CPU. The system will still work if this function is not implemented
-** (it is not currently implemented for win32), but it might be marginally
-** more efficient if it is.
-*/
-static void async_mutex_enter(int eMutex);
-static void async_mutex_leave(int eMutex);
-static void async_cond_wait(int eCond, int eMutex);
-static void async_cond_signal(int eCond);
-static void async_sched_yield(void);
-
-/*
-** There are also two definitions of the following. async_os_initialize()
-** is called when the asynchronous VFS is first installed, and os_shutdown()
-** is called when it is uninstalled (from within sqlite3async_shutdown()).
-**
-** For pthreads builds, both of these functions are no-ops. For win32,
-** they provide an opportunity to initialize and finalize the required
-** mutex and condition variables.
-**
-** If async_os_initialize() returns other than zero, then the initialization
-** fails and SQLITE_ERROR is returned to the user.
-*/
-static int async_os_initialize(void);
-static void async_os_shutdown(void);
-
-/* Values for use as the 'eMutex' argument of the above functions. The
-** integer values assigned to these constants are important for assert()
-** statements that verify that mutexes are locked in the correct order.
-** Specifically, it is unsafe to try to lock mutex N while holding a lock
-** on mutex M if (M<=N).
-*/
-#define ASYNC_MUTEX_LOCK 0
-#define ASYNC_MUTEX_QUEUE 1
-#define ASYNC_MUTEX_WRITER 2
-
-/* Values for use as the 'eCond' argument of the above functions. */
-#define ASYNC_COND_QUEUE 0
-
-/*************************************************************************
-** Start of OS specific code.
-*/
-#if SQLITE_OS_WIN || defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
-
-#include
-
-/* The following block contains the win32 specific code. */
-
-#define mutex_held(X) (GetCurrentThreadId()==primitives.aHolder[X])
-
-static struct AsyncPrimitives {
- int isInit;
- DWORD aHolder[3];
- CRITICAL_SECTION aMutex[3];
- HANDLE aCond[1];
-} primitives = { 0 };
-
-static int async_os_initialize(void){
- if( !primitives.isInit ){
- primitives.aCond[0] = CreateEvent(NULL, TRUE, FALSE, 0);
- if( primitives.aCond[0]==NULL ){
- return 1;
- }
- InitializeCriticalSection(&primitives.aMutex[0]);
- InitializeCriticalSection(&primitives.aMutex[1]);
- InitializeCriticalSection(&primitives.aMutex[2]);
- primitives.isInit = 1;
- }
- return 0;
-}
-static void async_os_shutdown(void){
- if( primitives.isInit ){
- DeleteCriticalSection(&primitives.aMutex[0]);
- DeleteCriticalSection(&primitives.aMutex[1]);
- DeleteCriticalSection(&primitives.aMutex[2]);
- CloseHandle(primitives.aCond[0]);
- primitives.isInit = 0;
- }
-}
-
-/* The following block contains the Win32 specific code. */
-static void async_mutex_enter(int eMutex){
- assert( eMutex==0 || eMutex==1 || eMutex==2 );
- assert( eMutex!=2 || (!mutex_held(0) && !mutex_held(1) && !mutex_held(2)) );
- assert( eMutex!=1 || (!mutex_held(0) && !mutex_held(1)) );
- assert( eMutex!=0 || (!mutex_held(0)) );
- EnterCriticalSection(&primitives.aMutex[eMutex]);
- TESTONLY( primitives.aHolder[eMutex] = GetCurrentThreadId(); )
-}
-static void async_mutex_leave(int eMutex){
- assert( eMutex==0 || eMutex==1 || eMutex==2 );
- assert( mutex_held(eMutex) );
- TESTONLY( primitives.aHolder[eMutex] = 0; )
- LeaveCriticalSection(&primitives.aMutex[eMutex]);
-}
-static void async_cond_wait(int eCond, int eMutex){
- ResetEvent(primitives.aCond[eCond]);
- async_mutex_leave(eMutex);
- WaitForSingleObject(primitives.aCond[eCond], INFINITE);
- async_mutex_enter(eMutex);
-}
-static void async_cond_signal(int eCond){
- assert( mutex_held(ASYNC_MUTEX_QUEUE) );
- SetEvent(primitives.aCond[eCond]);
-}
-static void async_sched_yield(void){
- Sleep(0);
-}
-#else
-
-/* The following block contains the pthreads specific code. */
-#include
-#include
-
-#define mutex_held(X) pthread_equal(primitives.aHolder[X], pthread_self())
-
-static int async_os_initialize(void) {return 0;}
-static void async_os_shutdown(void) {}
-
-static struct AsyncPrimitives {
- pthread_mutex_t aMutex[3];
- pthread_cond_t aCond[1];
- pthread_t aHolder[3];
-} primitives = {
- { PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_MUTEX_INITIALIZER
- } , {
- PTHREAD_COND_INITIALIZER
- } , { 0, 0, 0 }
-};
-
-static void async_mutex_enter(int eMutex){
- assert( eMutex==0 || eMutex==1 || eMutex==2 );
- assert( eMutex!=2 || (!mutex_held(0) && !mutex_held(1) && !mutex_held(2)) );
- assert( eMutex!=1 || (!mutex_held(0) && !mutex_held(1)) );
- assert( eMutex!=0 || (!mutex_held(0)) );
- pthread_mutex_lock(&primitives.aMutex[eMutex]);
- TESTONLY( primitives.aHolder[eMutex] = pthread_self(); )
-}
-static void async_mutex_leave(int eMutex){
- assert( eMutex==0 || eMutex==1 || eMutex==2 );
- assert( mutex_held(eMutex) );
- TESTONLY( primitives.aHolder[eMutex] = 0; )
- pthread_mutex_unlock(&primitives.aMutex[eMutex]);
-}
-static void async_cond_wait(int eCond, int eMutex){
- assert( eMutex==0 || eMutex==1 || eMutex==2 );
- assert( mutex_held(eMutex) );
- TESTONLY( primitives.aHolder[eMutex] = 0; )
- pthread_cond_wait(&primitives.aCond[eCond], &primitives.aMutex[eMutex]);
- TESTONLY( primitives.aHolder[eMutex] = pthread_self(); )
-}
-static void async_cond_signal(int eCond){
- assert( mutex_held(ASYNC_MUTEX_QUEUE) );
- pthread_cond_signal(&primitives.aCond[eCond]);
-}
-static void async_sched_yield(void){
- sched_yield();
-}
-#endif
-/*
-** End of OS specific code.
-*************************************************************************/
-
-#define assert_mutex_is_held(X) assert( mutex_held(X) )
-
-
-#ifndef SQLITE_ASYNC_TWO_FILEHANDLES
-/* #define SQLITE_ASYNC_TWO_FILEHANDLES 0 */
-#define SQLITE_ASYNC_TWO_FILEHANDLES 1
-#endif
-
-/*
-** State information is held in the static variable "async" defined
-** as the following structure.
-**
-** Both async.ioError and async.nFile are protected by async.queueMutex.
-*/
-static struct TestAsyncStaticData {
- AsyncWrite *pQueueFirst; /* Next write operation to be processed */
- AsyncWrite *pQueueLast; /* Last write operation on the list */
- AsyncLock *pLock; /* Linked list of all AsyncLock structures */
- volatile int ioDelay; /* Extra delay between write operations */
- volatile int eHalt; /* One of the SQLITEASYNC_HALT_XXX values */
- volatile int bLockFiles; /* Current value of "lockfiles" parameter */
- int ioError; /* True if an IO error has occurred */
- int nFile; /* Number of open files (from sqlite pov) */
-} async = { 0,0,0,0,0,1,0,0 };
-
-/* Possible values of AsyncWrite.op */
-#define ASYNC_NOOP 0
-#define ASYNC_WRITE 1
-#define ASYNC_SYNC 2
-#define ASYNC_TRUNCATE 3
-#define ASYNC_CLOSE 4
-#define ASYNC_DELETE 5
-#define ASYNC_OPENEXCLUSIVE 6
-#define ASYNC_UNLOCK 7
-
-/* Names of opcodes. Used for debugging only.
-** Make sure these stay in sync with the macros above!
-*/
-static const char *azOpcodeName[] = {
- "NOOP", "WRITE", "SYNC", "TRUNCATE", "CLOSE", "DELETE", "OPENEX", "UNLOCK"
-};
-
-/*
-** Entries on the write-op queue are instances of the AsyncWrite
-** structure, defined here.
-**
-** The interpretation of the iOffset and nByte variables varies depending
-** on the value of AsyncWrite.op:
-**
-** ASYNC_NOOP:
-** No values used.
-**
-** ASYNC_WRITE:
-** iOffset -> Offset in file to write to.
-** nByte -> Number of bytes of data to write (pointed to by zBuf).
-**
-** ASYNC_SYNC:
-** nByte -> flags to pass to sqlite3OsSync().
-**
-** ASYNC_TRUNCATE:
-** iOffset -> Size to truncate file to.
-** nByte -> Unused.
-**
-** ASYNC_CLOSE:
-** iOffset -> Unused.
-** nByte -> Unused.
-**
-** ASYNC_DELETE:
-** iOffset -> Contains the "syncDir" flag.
-** nByte -> Number of bytes of zBuf points to (file name).
-**
-** ASYNC_OPENEXCLUSIVE:
-** iOffset -> Value of "delflag".
-** nByte -> Number of bytes of zBuf points to (file name).
-**
-** ASYNC_UNLOCK:
-** nByte -> Argument to sqlite3OsUnlock().
-**
-**
-** For an ASYNC_WRITE operation, zBuf points to the data to write to the file.
-** This space is sqlite3_malloc()d along with the AsyncWrite structure in a
-** single blob, so is deleted when sqlite3_free() is called on the parent
-** structure.
-*/
-struct AsyncWrite {
- AsyncFileData *pFileData; /* File to write data to or sync */
- int op; /* One of ASYNC_xxx etc. */
- sqlite_int64 iOffset; /* See above */
- int nByte; /* See above */
- char *zBuf; /* Data to write to file (or NULL if op!=ASYNC_WRITE) */
- AsyncWrite *pNext; /* Next write operation (to any file) */
-};
-
-/*
-** An instance of this structure is created for each distinct open file
-** (i.e. if two handles are opened on the one file, only one of these
-** structures is allocated) and stored in the async.aLock hash table. The
-** keys for async.aLock are the full pathnames of the opened files.
-**
-** AsyncLock.pList points to the head of a linked list of AsyncFileLock
-** structures, one for each handle currently open on the file.
-**
-** If the opened file is not a main-database (the SQLITE_OPEN_MAIN_DB is
-** not passed to the sqlite3OsOpen() call), or if async.bLockFiles is
-** false, variables AsyncLock.pFile and AsyncLock.eLock are never used.
-** Otherwise, pFile is a file handle opened on the file in question and
-** used to obtain the file-system locks required by database connections
-** within this process.
-**
-** See comments above the asyncLock() function for more details on
-** the implementation of database locking used by this backend.
-*/
-struct AsyncLock {
- char *zFile;
- int nFile;
- sqlite3_file *pFile;
- int eLock;
- AsyncFileLock *pList;
- AsyncLock *pNext; /* Next in linked list headed by async.pLock */
-};
-
-/*
-** An instance of the following structure is allocated along with each
-** AsyncFileData structure (see AsyncFileData.lock), but is only used if the
-** file was opened with the SQLITE_OPEN_MAIN_DB.
-*/
-struct AsyncFileLock {
- int eLock; /* Internally visible lock state (sqlite pov) */
- int eAsyncLock; /* Lock-state with write-queue unlock */
- AsyncFileLock *pNext;
-};
-
-/*
-** The AsyncFile structure is a subclass of sqlite3_file used for
-** asynchronous IO.
-**
-** All of the actual data for the structure is stored in the structure
-** pointed to by AsyncFile.pData, which is allocated as part of the
-** sqlite3OsOpen() using sqlite3_malloc(). The reason for this is that the
-** lifetime of the AsyncFile structure is ended by the caller after OsClose()
-** is called, but the data in AsyncFileData may be required by the
-** writer thread after that point.
-*/
-struct AsyncFile {
- sqlite3_io_methods *pMethod;
- AsyncFileData *pData;
-};
-struct AsyncFileData {
- char *zName; /* Underlying OS filename - used for debugging */
- int nName; /* Number of characters in zName */
- sqlite3_file *pBaseRead; /* Read handle to the underlying Os file */
- sqlite3_file *pBaseWrite; /* Write handle to the underlying Os file */
- AsyncFileLock lock; /* Lock state for this handle */
- AsyncLock *pLock; /* AsyncLock object for this file system entry */
- AsyncWrite closeOp; /* Preallocated close operation */
-};
-
-/*
-** Add an entry to the end of the global write-op list. pWrite should point
-** to an AsyncWrite structure allocated using sqlite3_malloc(). The writer
-** thread will call sqlite3_free() to free the structure after the specified
-** operation has been completed.
-**
-** Once an AsyncWrite structure has been added to the list, it becomes the
-** property of the writer thread and must not be read or modified by the
-** caller.
-*/
-static void addAsyncWrite(AsyncWrite *pWrite){
- /* We must hold the queue mutex in order to modify the queue pointers */
- if( pWrite->op!=ASYNC_UNLOCK ){
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- }
-
- /* Add the record to the end of the write-op queue */
- assert( !pWrite->pNext );
- if( async.pQueueLast ){
- assert( async.pQueueFirst );
- async.pQueueLast->pNext = pWrite;
- }else{
- async.pQueueFirst = pWrite;
- }
- async.pQueueLast = pWrite;
- ASYNC_TRACE(("PUSH %p (%s %s %d)\n", pWrite, azOpcodeName[pWrite->op],
- pWrite->pFileData ? pWrite->pFileData->zName : "-", pWrite->iOffset));
-
- if( pWrite->op==ASYNC_CLOSE ){
- async.nFile--;
- }
-
- /* The writer thread might have been idle because there was nothing
- ** on the write-op queue for it to do. So wake it up. */
- async_cond_signal(ASYNC_COND_QUEUE);
-
- /* Drop the queue mutex */
- if( pWrite->op!=ASYNC_UNLOCK ){
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- }
-}
-
-/*
-** Increment async.nFile in a thread-safe manner.
-*/
-static void incrOpenFileCount(void){
- /* We must hold the queue mutex in order to modify async.nFile */
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- if( async.nFile==0 ){
- async.ioError = SQLITE_OK;
- }
- async.nFile++;
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
-}
-
-/*
-** This is a utility function to allocate and populate a new AsyncWrite
-** structure and insert it (via addAsyncWrite() ) into the global list.
-*/
-static int addNewAsyncWrite(
- AsyncFileData *pFileData,
- int op,
- sqlite3_int64 iOffset,
- int nByte,
- const char *zByte
-){
- AsyncWrite *p;
- if( op!=ASYNC_CLOSE && async.ioError ){
- return async.ioError;
- }
- p = sqlite3_malloc(sizeof(AsyncWrite) + (zByte?nByte:0));
- if( !p ){
- /* The upper layer does not expect operations like OsWrite() to
- ** return SQLITE_NOMEM. This is partly because under normal conditions
- ** SQLite is required to do rollback without calling malloc(). So
- ** if malloc() fails here, treat it as an I/O error. The above
- ** layer knows how to handle that.
- */
- return SQLITE_IOERR;
- }
- p->op = op;
- p->iOffset = iOffset;
- p->nByte = nByte;
- p->pFileData = pFileData;
- p->pNext = 0;
- if( zByte ){
- p->zBuf = (char *)&p[1];
- memcpy(p->zBuf, zByte, nByte);
- }else{
- p->zBuf = 0;
- }
- addAsyncWrite(p);
- return SQLITE_OK;
-}
-
-/*
-** Close the file. This just adds an entry to the write-op list, the file is
-** not actually closed.
-*/
-static int asyncClose(sqlite3_file *pFile){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
-
- /* Unlock the file, if it is locked */
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- p->lock.eLock = 0;
- async_mutex_leave(ASYNC_MUTEX_LOCK);
-
- addAsyncWrite(&p->closeOp);
- return SQLITE_OK;
-}
-
-/*
-** Implementation of sqlite3OsWrite() for asynchronous files. Instead of
-** writing to the underlying file, this function adds an entry to the end of
-** the global AsyncWrite list. Either SQLITE_OK or SQLITE_NOMEM may be
-** returned.
-*/
-static int asyncWrite(
- sqlite3_file *pFile,
- const void *pBuf,
- int amt,
- sqlite3_int64 iOff
-){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- return addNewAsyncWrite(p, ASYNC_WRITE, iOff, amt, pBuf);
-}
-
-/*
-** Read data from the file. First we read from the filesystem, then adjust
-** the contents of the buffer based on ASYNC_WRITE operations in the
-** write-op queue.
-**
-** This method holds the mutex from start to finish.
-*/
-static int asyncRead(
- sqlite3_file *pFile,
- void *zOut,
- int iAmt,
- sqlite3_int64 iOffset
-){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- int rc = SQLITE_OK;
- sqlite3_int64 filesize = 0;
- sqlite3_file *pBase = p->pBaseRead;
- sqlite3_int64 iAmt64 = (sqlite3_int64)iAmt;
-
- /* Grab the write queue mutex for the duration of the call */
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
-
- /* If an I/O error has previously occurred in this virtual file
- ** system, then all subsequent operations fail.
- */
- if( async.ioError!=SQLITE_OK ){
- rc = async.ioError;
- goto asyncread_out;
- }
-
- if( pBase->pMethods ){
- sqlite3_int64 nRead;
- rc = pBase->pMethods->xFileSize(pBase, &filesize);
- if( rc!=SQLITE_OK ){
- goto asyncread_out;
- }
- nRead = MIN(filesize - iOffset, iAmt64);
- if( nRead>0 ){
- rc = pBase->pMethods->xRead(pBase, zOut, (int)nRead, iOffset);
- ASYNC_TRACE(("READ %s %d bytes at %d\n", p->zName, nRead, iOffset));
- }
- }
-
- if( rc==SQLITE_OK ){
- AsyncWrite *pWrite;
- char *zName = p->zName;
-
- for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
- if( pWrite->op==ASYNC_WRITE && (
- (pWrite->pFileData==p) ||
- (zName && pWrite->pFileData->zName==zName)
- )){
- sqlite3_int64 nCopy;
- sqlite3_int64 nByte64 = (sqlite3_int64)pWrite->nByte;
-
- /* Set variable iBeginIn to the offset in buffer pWrite->zBuf[] from
- ** which data should be copied. Set iBeginOut to the offset within
- ** the output buffer to which data should be copied. If either of
- ** these offsets is a negative number, set them to 0.
- */
- sqlite3_int64 iBeginOut = (pWrite->iOffset-iOffset);
- sqlite3_int64 iBeginIn = -iBeginOut;
- if( iBeginIn<0 ) iBeginIn = 0;
- if( iBeginOut<0 ) iBeginOut = 0;
-
- filesize = MAX(filesize, pWrite->iOffset+nByte64);
-
- nCopy = MIN(nByte64-iBeginIn, iAmt64-iBeginOut);
- if( nCopy>0 ){
- memcpy(&((char *)zOut)[iBeginOut], &pWrite->zBuf[iBeginIn], (size_t)nCopy);
- ASYNC_TRACE(("OVERREAD %d bytes at %d\n", nCopy, iBeginOut+iOffset));
- }
- }
- }
- }
-
-asyncread_out:
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- if( rc==SQLITE_OK && filesize<(iOffset+iAmt) ){
- rc = SQLITE_IOERR_SHORT_READ;
- }
- return rc;
-}
-
-/*
-** Truncate the file to nByte bytes in length. This just adds an entry to
-** the write-op list, no IO actually takes place.
-*/
-static int asyncTruncate(sqlite3_file *pFile, sqlite3_int64 nByte){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- return addNewAsyncWrite(p, ASYNC_TRUNCATE, nByte, 0, 0);
-}
-
-/*
-** Sync the file. This just adds an entry to the write-op list, the
-** sync() is done later by sqlite3_async_flush().
-*/
-static int asyncSync(sqlite3_file *pFile, int flags){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- return addNewAsyncWrite(p, ASYNC_SYNC, 0, flags, 0);
-}
-
-/*
-** Read the size of the file. First we read the size of the file system
-** entry, then adjust for any ASYNC_WRITE or ASYNC_TRUNCATE operations
-** currently in the write-op list.
-**
-** This method holds the mutex from start to finish.
-*/
-int asyncFileSize(sqlite3_file *pFile, sqlite3_int64 *piSize){
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- int rc = SQLITE_OK;
- sqlite3_int64 s = 0;
- sqlite3_file *pBase;
-
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
-
- /* Read the filesystem size from the base file. If pMethods is NULL, this
- ** means the file hasn't been opened yet. In this case all relevant data
- ** must be in the write-op queue anyway, so we can omit reading from the
- ** file-system.
- */
- pBase = p->pBaseRead;
- if( pBase->pMethods ){
- rc = pBase->pMethods->xFileSize(pBase, &s);
- }
-
- if( rc==SQLITE_OK ){
- AsyncWrite *pWrite;
- for(pWrite=async.pQueueFirst; pWrite; pWrite = pWrite->pNext){
- if( pWrite->op==ASYNC_DELETE
- && p->zName
- && strcmp(p->zName, pWrite->zBuf)==0
- ){
- s = 0;
- }else if( pWrite->pFileData && (
- (pWrite->pFileData==p)
- || (p->zName && pWrite->pFileData->zName==p->zName)
- )){
- switch( pWrite->op ){
- case ASYNC_WRITE:
- s = MAX(pWrite->iOffset + (sqlite3_int64)(pWrite->nByte), s);
- break;
- case ASYNC_TRUNCATE:
- s = MIN(s, pWrite->iOffset);
- break;
- }
- }
- }
- *piSize = s;
- }
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- return rc;
-}
-
-/*
-** Lock or unlock the actual file-system entry.
-*/
-static int getFileLock(AsyncLock *pLock){
- int rc = SQLITE_OK;
- AsyncFileLock *pIter;
- int eRequired = 0;
-
- if( pLock->pFile ){
- for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
- assert(pIter->eAsyncLock>=pIter->eLock);
- if( pIter->eAsyncLock>eRequired ){
- eRequired = pIter->eAsyncLock;
- assert(eRequired>=0 && eRequired<=SQLITE_LOCK_EXCLUSIVE);
- }
- }
-
- if( eRequired>pLock->eLock ){
- rc = pLock->pFile->pMethods->xLock(pLock->pFile, eRequired);
- if( rc==SQLITE_OK ){
- pLock->eLock = eRequired;
- }
- }
- else if( eRequiredeLock && eRequired<=SQLITE_LOCK_SHARED ){
- rc = pLock->pFile->pMethods->xUnlock(pLock->pFile, eRequired);
- if( rc==SQLITE_OK ){
- pLock->eLock = eRequired;
- }
- }
- }
-
- return rc;
-}
-
-/*
-** Return the AsyncLock structure from the global async.pLock list
-** associated with the file-system entry identified by path zName
-** (a string of nName bytes). If no such structure exists, return 0.
-*/
-static AsyncLock *findLock(const char *zName, int nName){
- AsyncLock *p = async.pLock;
- while( p && (p->nFile!=nName || memcmp(p->zFile, zName, nName)) ){
- p = p->pNext;
- }
- return p;
-}
-
-/*
-** The following two methods - asyncLock() and asyncUnlock() - are used
-** to obtain and release locks on database files opened with the
-** asynchronous backend.
-*/
-static int asyncLock(sqlite3_file *pFile, int eLock){
- int rc = SQLITE_OK;
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
-
- if( p->zName ){
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- if( p->lock.eLockpLock;
- AsyncFileLock *pIter;
- assert(pLock && pLock->pList);
- for(pIter=pLock->pList; pIter; pIter=pIter->pNext){
- if( pIter!=&p->lock && (
- (eLock==SQLITE_LOCK_EXCLUSIVE && pIter->eLock>=SQLITE_LOCK_SHARED) ||
- (eLock==SQLITE_LOCK_PENDING && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
- (eLock==SQLITE_LOCK_RESERVED && pIter->eLock>=SQLITE_LOCK_RESERVED) ||
- (eLock==SQLITE_LOCK_SHARED && pIter->eLock>=SQLITE_LOCK_PENDING)
- )){
- rc = SQLITE_BUSY;
- }
- }
- if( rc==SQLITE_OK ){
- p->lock.eLock = eLock;
- p->lock.eAsyncLock = MAX(p->lock.eAsyncLock, eLock);
- }
- assert(p->lock.eAsyncLock>=p->lock.eLock);
- if( rc==SQLITE_OK ){
- rc = getFileLock(pLock);
- }
- }
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- }
-
- ASYNC_TRACE(("LOCK %d (%s) rc=%d\n", eLock, p->zName, rc));
- return rc;
-}
-static int asyncUnlock(sqlite3_file *pFile, int eLock){
- int rc = SQLITE_OK;
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
- if( p->zName ){
- AsyncFileLock *pLock = &p->lock;
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- pLock->eLock = MIN(pLock->eLock, eLock);
- rc = addNewAsyncWrite(p, ASYNC_UNLOCK, 0, eLock, 0);
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- }
- return rc;
-}
-
-/*
-** This function is called when the pager layer first opens a database file
-** and is checking for a hot-journal.
-*/
-static int asyncCheckReservedLock(sqlite3_file *pFile, int *pResOut){
- int ret = 0;
- AsyncFileLock *pIter;
- AsyncFileData *p = ((AsyncFile *)pFile)->pData;
-
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- for(pIter=p->pLock->pList; pIter; pIter=pIter->pNext){
- if( pIter->eLock>=SQLITE_LOCK_RESERVED ){
- ret = 1;
- break;
- }
- }
- async_mutex_leave(ASYNC_MUTEX_LOCK);
-
- ASYNC_TRACE(("CHECK-LOCK %d (%s)\n", ret, p->zName));
- *pResOut = ret;
- return SQLITE_OK;
-}
-
-/*
-** sqlite3_file_control() implementation.
-*/
-static int asyncFileControl(sqlite3_file *id, int op, void *pArg){
- switch( op ){
- case SQLITE_FCNTL_LOCKSTATE: {
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- *(int*)pArg = ((AsyncFile*)id)->pData->lock.eLock;
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- return SQLITE_OK;
- }
- }
- return SQLITE_NOTFOUND;
-}
-
-/*
-** Return the device characteristics and sector-size of the device. It
-** is tricky to implement these correctly, as this backend might
-** not have an open file handle at this point.
-*/
-static int asyncSectorSize(sqlite3_file *pFile){
- UNUSED_PARAMETER(pFile);
- return 512;
-}
-static int asyncDeviceCharacteristics(sqlite3_file *pFile){
- UNUSED_PARAMETER(pFile);
- return 0;
-}
-
-static int unlinkAsyncFile(AsyncFileData *pData){
- AsyncFileLock **ppIter;
- int rc = SQLITE_OK;
-
- if( pData->zName ){
- AsyncLock *pLock = pData->pLock;
- for(ppIter=&pLock->pList; *ppIter; ppIter=&((*ppIter)->pNext)){
- if( (*ppIter)==&pData->lock ){
- *ppIter = pData->lock.pNext;
- break;
- }
- }
- if( !pLock->pList ){
- AsyncLock **pp;
- if( pLock->pFile ){
- pLock->pFile->pMethods->xClose(pLock->pFile);
- }
- for(pp=&async.pLock; *pp!=pLock; pp=&((*pp)->pNext));
- *pp = pLock->pNext;
- sqlite3_free(pLock);
- }else{
- rc = getFileLock(pLock);
- }
- }
-
- return rc;
-}
-
-/*
-** The parameter passed to this function is a copy of a 'flags' parameter
-** passed to this modules xOpen() method. This function returns true
-** if the file should be opened asynchronously, or false if it should
-** be opened immediately.
-**
-** If the file is to be opened asynchronously, then asyncOpen() will add
-** an entry to the event queue and the file will not actually be opened
-** until the event is processed. Otherwise, the file is opened directly
-** by the caller.
-*/
-static int doAsynchronousOpen(int flags){
- return (flags&SQLITE_OPEN_CREATE) && (
- (flags&SQLITE_OPEN_MAIN_JOURNAL) ||
- (flags&SQLITE_OPEN_TEMP_JOURNAL) ||
- (flags&SQLITE_OPEN_DELETEONCLOSE)
- );
-}
-
-/*
-** Open a file.
-*/
-static int asyncOpen(
- sqlite3_vfs *pAsyncVfs,
- const char *zName,
- sqlite3_file *pFile,
- int flags,
- int *pOutFlags
-){
- static sqlite3_io_methods async_methods = {
- 1, /* iVersion */
- asyncClose, /* xClose */
- asyncRead, /* xRead */
- asyncWrite, /* xWrite */
- asyncTruncate, /* xTruncate */
- asyncSync, /* xSync */
- asyncFileSize, /* xFileSize */
- asyncLock, /* xLock */
- asyncUnlock, /* xUnlock */
- asyncCheckReservedLock, /* xCheckReservedLock */
- asyncFileControl, /* xFileControl */
- asyncSectorSize, /* xSectorSize */
- asyncDeviceCharacteristics /* xDeviceCharacteristics */
- };
-
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- AsyncFile *p = (AsyncFile *)pFile;
- int nName = 0;
- int rc = SQLITE_OK;
- int nByte;
- AsyncFileData *pData;
- AsyncLock *pLock = 0;
- char *z;
- int isAsyncOpen = doAsynchronousOpen(flags);
-
- /* If zName is NULL, then the upper layer is requesting an anonymous file.
- ** Otherwise, allocate enough space to make a copy of the file name (along
- ** with the second nul-terminator byte required by xOpen).
- */
- if( zName ){
- nName = (int)strlen(zName);
- }
-
- nByte = (
- sizeof(AsyncFileData) + /* AsyncFileData structure */
- 2 * pVfs->szOsFile + /* AsyncFileData.pBaseRead and pBaseWrite */
- nName + 2 /* AsyncFileData.zName */
- );
- z = sqlite3_malloc(nByte);
- if( !z ){
- return SQLITE_NOMEM;
- }
- memset(z, 0, nByte);
- pData = (AsyncFileData*)z;
- z += sizeof(pData[0]);
- pData->pBaseRead = (sqlite3_file*)z;
- z += pVfs->szOsFile;
- pData->pBaseWrite = (sqlite3_file*)z;
- pData->closeOp.pFileData = pData;
- pData->closeOp.op = ASYNC_CLOSE;
-
- if( zName ){
- z += pVfs->szOsFile;
- pData->zName = z;
- pData->nName = nName;
- memcpy(pData->zName, zName, nName);
- }
-
- if( !isAsyncOpen ){
- int flagsout;
- rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, &flagsout);
- if( rc==SQLITE_OK
- && (flagsout&SQLITE_OPEN_READWRITE)
- && (flags&SQLITE_OPEN_EXCLUSIVE)==0
- ){
- rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseWrite, flags, 0);
- }
- if( pOutFlags ){
- *pOutFlags = flagsout;
- }
- }
-
- async_mutex_enter(ASYNC_MUTEX_LOCK);
-
- if( zName && rc==SQLITE_OK ){
- pLock = findLock(pData->zName, pData->nName);
- if( !pLock ){
- int nByte = pVfs->szOsFile + sizeof(AsyncLock) + pData->nName + 1;
- pLock = (AsyncLock *)sqlite3_malloc(nByte);
- if( pLock ){
- memset(pLock, 0, nByte);
- if( async.bLockFiles && (flags&SQLITE_OPEN_MAIN_DB) ){
- pLock->pFile = (sqlite3_file *)&pLock[1];
- rc = pVfs->xOpen(pVfs, pData->zName, pLock->pFile, flags, 0);
- if( rc!=SQLITE_OK ){
- sqlite3_free(pLock);
- pLock = 0;
- }
- }
- if( pLock ){
- pLock->nFile = pData->nName;
- pLock->zFile = &((char *)(&pLock[1]))[pVfs->szOsFile];
- memcpy(pLock->zFile, pData->zName, pLock->nFile);
- pLock->pNext = async.pLock;
- async.pLock = pLock;
- }
- }else{
- rc = SQLITE_NOMEM;
- }
- }
- }
-
- if( rc==SQLITE_OK ){
- p->pMethod = &async_methods;
- p->pData = pData;
-
- /* Link AsyncFileData.lock into the linked list of
- ** AsyncFileLock structures for this file.
- */
- if( zName ){
- pData->lock.pNext = pLock->pList;
- pLock->pList = &pData->lock;
- pData->zName = pLock->zFile;
- }
- }else{
- if( pData->pBaseRead->pMethods ){
- pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
- }
- if( pData->pBaseWrite->pMethods ){
- pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
- }
- sqlite3_free(pData);
- }
-
- async_mutex_leave(ASYNC_MUTEX_LOCK);
-
- if( rc==SQLITE_OK ){
- pData->pLock = pLock;
- }
-
- if( rc==SQLITE_OK && isAsyncOpen ){
- rc = addNewAsyncWrite(pData, ASYNC_OPENEXCLUSIVE, (sqlite3_int64)flags,0,0);
- if( rc==SQLITE_OK ){
- if( pOutFlags ) *pOutFlags = flags;
- }else{
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- unlinkAsyncFile(pData);
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- sqlite3_free(pData);
- }
- }
- if( rc!=SQLITE_OK ){
- p->pMethod = 0;
- }else{
- incrOpenFileCount();
- }
-
- return rc;
-}
-
-/*
-** Implementation of sqlite3OsDelete. Add an entry to the end of the
-** write-op queue to perform the delete.
-*/
-static int asyncDelete(sqlite3_vfs *pAsyncVfs, const char *z, int syncDir){
- UNUSED_PARAMETER(pAsyncVfs);
- return addNewAsyncWrite(0, ASYNC_DELETE, syncDir, (int)strlen(z)+1, z);
-}
-
-/*
-** Implementation of sqlite3OsAccess. This method holds the mutex from
-** start to finish.
-*/
-static int asyncAccess(
- sqlite3_vfs *pAsyncVfs,
- const char *zName,
- int flags,
- int *pResOut
-){
- int rc;
- int ret;
- AsyncWrite *p;
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
-
- assert(flags==SQLITE_ACCESS_READWRITE
- || flags==SQLITE_ACCESS_READ
- || flags==SQLITE_ACCESS_EXISTS
- );
-
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- rc = pVfs->xAccess(pVfs, zName, flags, &ret);
- if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){
- for(p=async.pQueueFirst; p; p = p->pNext){
- if( p->op==ASYNC_DELETE && 0==strcmp(p->zBuf, zName) ){
- ret = 0;
- }else if( p->op==ASYNC_OPENEXCLUSIVE
- && p->pFileData->zName
- && 0==strcmp(p->pFileData->zName, zName)
- ){
- ret = 1;
- }
- }
- }
- ASYNC_TRACE(("ACCESS(%s): %s = %d\n",
- flags==SQLITE_ACCESS_READWRITE?"read-write":
- flags==SQLITE_ACCESS_READ?"read":"exists"
- , zName, ret)
- );
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- *pResOut = ret;
- return rc;
-}
-
-/*
-** Fill in zPathOut with the full path to the file identified by zPath.
-*/
-static int asyncFullPathname(
- sqlite3_vfs *pAsyncVfs,
- const char *zPath,
- int nPathOut,
- char *zPathOut
-){
- int rc;
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- rc = pVfs->xFullPathname(pVfs, zPath, nPathOut, zPathOut);
-
- /* Because of the way intra-process file locking works, this backend
- ** needs to return a canonical path. The following block assumes the
- ** file-system uses unix style paths.
- */
- if( rc==SQLITE_OK ){
- int i, j;
- char *z = zPathOut;
- int n = (int)strlen(z);
- while( n>1 && z[n-1]=='/' ){ n--; }
- for(i=j=0; i0 && z[j-1]!='/' ){ j--; }
- if( j>0 ){ j--; }
- i += 2;
- continue;
- }
- }
- z[j++] = z[i];
- }
- z[j] = 0;
- }
-
- return rc;
-}
-static void *asyncDlOpen(sqlite3_vfs *pAsyncVfs, const char *zPath){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- return pVfs->xDlOpen(pVfs, zPath);
-}
-static void asyncDlError(sqlite3_vfs *pAsyncVfs, int nByte, char *zErrMsg){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- pVfs->xDlError(pVfs, nByte, zErrMsg);
-}
-static void (*asyncDlSym(
- sqlite3_vfs *pAsyncVfs,
- void *pHandle,
- const char *zSymbol
-))(void){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- return pVfs->xDlSym(pVfs, pHandle, zSymbol);
-}
-static void asyncDlClose(sqlite3_vfs *pAsyncVfs, void *pHandle){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- pVfs->xDlClose(pVfs, pHandle);
-}
-static int asyncRandomness(sqlite3_vfs *pAsyncVfs, int nByte, char *zBufOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- return pVfs->xRandomness(pVfs, nByte, zBufOut);
-}
-static int asyncSleep(sqlite3_vfs *pAsyncVfs, int nMicro){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- return pVfs->xSleep(pVfs, nMicro);
-}
-static int asyncCurrentTime(sqlite3_vfs *pAsyncVfs, double *pTimeOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAsyncVfs->pAppData;
- return pVfs->xCurrentTime(pVfs, pTimeOut);
-}
-
-static sqlite3_vfs async_vfs = {
- 1, /* iVersion */
- sizeof(AsyncFile), /* szOsFile */
- 0, /* mxPathname */
- 0, /* pNext */
- SQLITEASYNC_VFSNAME, /* zName */
- 0, /* pAppData */
- asyncOpen, /* xOpen */
- asyncDelete, /* xDelete */
- asyncAccess, /* xAccess */
- asyncFullPathname, /* xFullPathname */
- asyncDlOpen, /* xDlOpen */
- asyncDlError, /* xDlError */
- asyncDlSym, /* xDlSym */
- asyncDlClose, /* xDlClose */
- asyncRandomness, /* xDlError */
- asyncSleep, /* xDlSym */
- asyncCurrentTime /* xDlClose */
-};
-
-/*
-** This procedure runs in a separate thread, reading messages off of the
-** write queue and processing them one by one.
-**
-** If async.writerHaltNow is true, then this procedure exits
-** after processing a single message.
-**
-** If async.writerHaltWhenIdle is true, then this procedure exits when
-** the write queue is empty.
-**
-** If both of the above variables are false, this procedure runs
-** indefinately, waiting for operations to be added to the write queue
-** and processing them in the order in which they arrive.
-**
-** An artifical delay of async.ioDelay milliseconds is inserted before
-** each write operation in order to simulate the effect of a slow disk.
-**
-** Only one instance of this procedure may be running at a time.
-*/
-static void asyncWriterThread(void){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)(async_vfs.pAppData);
- AsyncWrite *p = 0;
- int rc = SQLITE_OK;
- int holdingMutex = 0;
-
- async_mutex_enter(ASYNC_MUTEX_WRITER);
-
- while( async.eHalt!=SQLITEASYNC_HALT_NOW ){
- int doNotFree = 0;
- sqlite3_file *pBase = 0;
-
- if( !holdingMutex ){
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- }
- while( (p = async.pQueueFirst)==0 ){
- if( async.eHalt!=SQLITEASYNC_HALT_NEVER ){
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- break;
- }else{
- ASYNC_TRACE(("IDLE\n"));
- async_cond_wait(ASYNC_COND_QUEUE, ASYNC_MUTEX_QUEUE);
- ASYNC_TRACE(("WAKEUP\n"));
- }
- }
- if( p==0 ) break;
- holdingMutex = 1;
-
- /* Right now this thread is holding the mutex on the write-op queue.
- ** Variable 'p' points to the first entry in the write-op queue. In
- ** the general case, we hold on to the mutex for the entire body of
- ** the loop.
- **
- ** However in the cases enumerated below, we relinquish the mutex,
- ** perform the IO, and then re-request the mutex before removing 'p' from
- ** the head of the write-op queue. The idea is to increase concurrency with
- ** sqlite threads.
- **
- ** * An ASYNC_CLOSE operation.
- ** * An ASYNC_OPENEXCLUSIVE operation. For this one, we relinquish
- ** the mutex, call the underlying xOpenExclusive() function, then
- ** re-aquire the mutex before seting the AsyncFile.pBaseRead
- ** variable.
- ** * ASYNC_SYNC and ASYNC_WRITE operations, if
- ** SQLITE_ASYNC_TWO_FILEHANDLES was set at compile time and two
- ** file-handles are open for the particular file being "synced".
- */
- if( async.ioError!=SQLITE_OK && p->op!=ASYNC_CLOSE ){
- p->op = ASYNC_NOOP;
- }
- if( p->pFileData ){
- pBase = p->pFileData->pBaseWrite;
- if(
- p->op==ASYNC_CLOSE ||
- p->op==ASYNC_OPENEXCLUSIVE ||
- (pBase->pMethods && (p->op==ASYNC_SYNC || p->op==ASYNC_WRITE) )
- ){
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- holdingMutex = 0;
- }
- if( !pBase->pMethods ){
- pBase = p->pFileData->pBaseRead;
- }
- }
-
- switch( p->op ){
- case ASYNC_NOOP:
- break;
-
- case ASYNC_WRITE:
- assert( pBase );
- ASYNC_TRACE(("WRITE %s %d bytes at %d\n",
- p->pFileData->zName, p->nByte, p->iOffset));
- rc = pBase->pMethods->xWrite(pBase, (void *)(p->zBuf), p->nByte, p->iOffset);
- break;
-
- case ASYNC_SYNC:
- assert( pBase );
- ASYNC_TRACE(("SYNC %s\n", p->pFileData->zName));
- rc = pBase->pMethods->xSync(pBase, p->nByte);
- break;
-
- case ASYNC_TRUNCATE:
- assert( pBase );
- ASYNC_TRACE(("TRUNCATE %s to %d bytes\n",
- p->pFileData->zName, p->iOffset));
- rc = pBase->pMethods->xTruncate(pBase, p->iOffset);
- break;
-
- case ASYNC_CLOSE: {
- AsyncFileData *pData = p->pFileData;
- ASYNC_TRACE(("CLOSE %s\n", p->pFileData->zName));
- if( pData->pBaseWrite->pMethods ){
- pData->pBaseWrite->pMethods->xClose(pData->pBaseWrite);
- }
- if( pData->pBaseRead->pMethods ){
- pData->pBaseRead->pMethods->xClose(pData->pBaseRead);
- }
-
- /* Unlink AsyncFileData.lock from the linked list of AsyncFileLock
- ** structures for this file. Obtain the async.lockMutex mutex
- ** before doing so.
- */
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- rc = unlinkAsyncFile(pData);
- async_mutex_leave(ASYNC_MUTEX_LOCK);
-
- if( !holdingMutex ){
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- holdingMutex = 1;
- }
- assert_mutex_is_held(ASYNC_MUTEX_QUEUE);
- async.pQueueFirst = p->pNext;
- sqlite3_free(pData);
- doNotFree = 1;
- break;
- }
-
- case ASYNC_UNLOCK: {
- AsyncWrite *pIter;
- AsyncFileData *pData = p->pFileData;
- int eLock = p->nByte;
-
- /* When a file is locked by SQLite using the async backend, it is
- ** locked within the 'real' file-system synchronously. When it is
- ** unlocked, an ASYNC_UNLOCK event is added to the write-queue to
- ** unlock the file asynchronously. The design of the async backend
- ** requires that the 'real' file-system file be locked from the
- ** time that SQLite first locks it (and probably reads from it)
- ** until all asynchronous write events that were scheduled before
- ** SQLite unlocked the file have been processed.
- **
- ** This is more complex if SQLite locks and unlocks the file multiple
- ** times in quick succession. For example, if SQLite does:
- **
- ** lock, write, unlock, lock, write, unlock
- **
- ** Each "lock" operation locks the file immediately. Each "write"
- ** and "unlock" operation adds an event to the event queue. If the
- ** second "lock" operation is performed before the first "unlock"
- ** operation has been processed asynchronously, then the first
- ** "unlock" cannot be safely processed as is, since this would mean
- ** the file was unlocked when the second "write" operation is
- ** processed. To work around this, when processing an ASYNC_UNLOCK
- ** operation, SQLite:
- **
- ** 1) Unlocks the file to the minimum of the argument passed to
- ** the xUnlock() call and the current lock from SQLite's point
- ** of view, and
- **
- ** 2) Only unlocks the file at all if this event is the last
- ** ASYNC_UNLOCK event on this file in the write-queue.
- */
- assert( holdingMutex==1 );
- assert( async.pQueueFirst==p );
- for(pIter=async.pQueueFirst->pNext; pIter; pIter=pIter->pNext){
- if( pIter->pFileData==pData && pIter->op==ASYNC_UNLOCK ) break;
- }
- if( !pIter ){
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- pData->lock.eAsyncLock = MIN(
- pData->lock.eAsyncLock, MAX(pData->lock.eLock, eLock)
- );
- assert(pData->lock.eAsyncLock>=pData->lock.eLock);
- rc = getFileLock(pData->pLock);
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- }
- break;
- }
-
- case ASYNC_DELETE:
- ASYNC_TRACE(("DELETE %s\n", p->zBuf));
- rc = pVfs->xDelete(pVfs, p->zBuf, (int)p->iOffset);
- if( rc==SQLITE_IOERR_DELETE_NOENT ) rc = SQLITE_OK;
- break;
-
- case ASYNC_OPENEXCLUSIVE: {
- int flags = (int)p->iOffset;
- AsyncFileData *pData = p->pFileData;
- ASYNC_TRACE(("OPEN %s flags=%d\n", p->zBuf, (int)p->iOffset));
- assert(pData->pBaseRead->pMethods==0 && pData->pBaseWrite->pMethods==0);
- rc = pVfs->xOpen(pVfs, pData->zName, pData->pBaseRead, flags, 0);
- assert( holdingMutex==0 );
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- holdingMutex = 1;
- break;
- }
-
- default: assert(!"Illegal value for AsyncWrite.op");
- }
-
- /* If we didn't hang on to the mutex during the IO op, obtain it now
- ** so that the AsyncWrite structure can be safely removed from the
- ** global write-op queue.
- */
- if( !holdingMutex ){
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- holdingMutex = 1;
- }
- /* ASYNC_TRACE(("UNLINK %p\n", p)); */
- if( p==async.pQueueLast ){
- async.pQueueLast = 0;
- }
- if( !doNotFree ){
- assert_mutex_is_held(ASYNC_MUTEX_QUEUE);
- async.pQueueFirst = p->pNext;
- sqlite3_free(p);
- }
- assert( holdingMutex );
-
- /* An IO error has occurred. We cannot report the error back to the
- ** connection that requested the I/O since the error happened
- ** asynchronously. The connection has already moved on. There
- ** really is nobody to report the error to.
- **
- ** The file for which the error occurred may have been a database or
- ** journal file. Regardless, none of the currently queued operations
- ** associated with the same database should now be performed. Nor should
- ** any subsequently requested IO on either a database or journal file
- ** handle for the same database be accepted until the main database
- ** file handle has been closed and reopened.
- **
- ** Furthermore, no further IO should be queued or performed on any file
- ** handle associated with a database that may have been part of a
- ** multi-file transaction that included the database associated with
- ** the IO error (i.e. a database ATTACHed to the same handle at some
- ** point in time).
- */
- if( rc!=SQLITE_OK ){
- async.ioError = rc;
- }
-
- if( async.ioError && !async.pQueueFirst ){
- async_mutex_enter(ASYNC_MUTEX_LOCK);
- if( 0==async.pLock ){
- async.ioError = SQLITE_OK;
- }
- async_mutex_leave(ASYNC_MUTEX_LOCK);
- }
-
- /* Drop the queue mutex before continuing to the next write operation
- ** in order to give other threads a chance to work with the write queue.
- */
- if( !async.pQueueFirst || !async.ioError ){
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- holdingMutex = 0;
- if( async.ioDelay>0 ){
- pVfs->xSleep(pVfs, async.ioDelay*1000);
- }else{
- async_sched_yield();
- }
- }
- }
-
- async_mutex_leave(ASYNC_MUTEX_WRITER);
- return;
-}
-
-/*
-** Install the asynchronous VFS.
-*/
-int sqlite3async_initialize(const char *zParent, int isDefault){
- int rc = SQLITE_OK;
- if( async_vfs.pAppData==0 ){
- sqlite3_vfs *pParent = sqlite3_vfs_find(zParent);
- if( !pParent || async_os_initialize() ){
- rc = SQLITE_ERROR;
- }else if( SQLITE_OK!=(rc = sqlite3_vfs_register(&async_vfs, isDefault)) ){
- async_os_shutdown();
- }else{
- async_vfs.pAppData = (void *)pParent;
- async_vfs.mxPathname = ((sqlite3_vfs *)async_vfs.pAppData)->mxPathname;
- }
- }
- return rc;
-}
-
-/*
-** Uninstall the asynchronous VFS.
-*/
-void sqlite3async_shutdown(void){
- if( async_vfs.pAppData ){
- async_os_shutdown();
- sqlite3_vfs_unregister((sqlite3_vfs *)&async_vfs);
- async_vfs.pAppData = 0;
- }
-}
-
-/*
-** Process events on the write-queue.
-*/
-void sqlite3async_run(void){
- asyncWriterThread();
-}
-
-/*
-** Control/configure the asynchronous IO system.
-*/
-int sqlite3async_control(int op, ...){
- int rc = SQLITE_OK;
- va_list ap;
- va_start(ap, op);
- switch( op ){
- case SQLITEASYNC_HALT: {
- int eWhen = va_arg(ap, int);
- if( eWhen!=SQLITEASYNC_HALT_NEVER
- && eWhen!=SQLITEASYNC_HALT_NOW
- && eWhen!=SQLITEASYNC_HALT_IDLE
- ){
- rc = SQLITE_MISUSE;
- break;
- }
- async.eHalt = eWhen;
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- async_cond_signal(ASYNC_COND_QUEUE);
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- break;
- }
-
- case SQLITEASYNC_DELAY: {
- int iDelay = va_arg(ap, int);
- if( iDelay<0 ){
- rc = SQLITE_MISUSE;
- break;
- }
- async.ioDelay = iDelay;
- break;
- }
-
- case SQLITEASYNC_LOCKFILES: {
- int bLock = va_arg(ap, int);
- async_mutex_enter(ASYNC_MUTEX_QUEUE);
- if( async.nFile || async.pQueueFirst ){
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- rc = SQLITE_MISUSE;
- break;
- }
- async.bLockFiles = bLock;
- async_mutex_leave(ASYNC_MUTEX_QUEUE);
- break;
- }
-
- case SQLITEASYNC_GET_HALT: {
- int *peWhen = va_arg(ap, int *);
- *peWhen = async.eHalt;
- break;
- }
- case SQLITEASYNC_GET_DELAY: {
- int *piDelay = va_arg(ap, int *);
- *piDelay = async.ioDelay;
- break;
- }
- case SQLITEASYNC_GET_LOCKFILES: {
- int *piDelay = va_arg(ap, int *);
- *piDelay = async.bLockFiles;
- break;
- }
-
- default:
- rc = SQLITE_ERROR;
- break;
- }
- va_end(ap);
- return rc;
-}
-
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ASYNCIO) */
diff --git a/ext/async/sqlite3async.h b/ext/async/sqlite3async.h
deleted file mode 100644
index 13b23bc6a2..0000000000
--- a/ext/async/sqlite3async.h
+++ /dev/null
@@ -1,222 +0,0 @@
-
-#ifndef __SQLITEASYNC_H_
-#define __SQLITEASYNC_H_ 1
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SQLITEASYNC_VFSNAME "sqlite3async"
-
-/*
-** THREAD SAFETY NOTES:
-**
-** Of the four API functions in this file, the following are not threadsafe:
-**
-** sqlite3async_initialize()
-** sqlite3async_shutdown()
-**
-** Care must be taken that neither of these functions is called while
-** another thread may be calling either any sqlite3async_XXX() function
-** or an sqlite3_XXX() API function related to a database handle that
-** is using the asynchronous IO VFS.
-**
-** These functions:
-**
-** sqlite3async_run()
-** sqlite3async_control()
-**
-** are threadsafe. It is quite safe to call either of these functions even
-** if another thread may also be calling one of them or an sqlite3_XXX()
-** function related to a database handle that uses the asynchronous IO VFS.
-*/
-
-/*
-** Initialize the asynchronous IO VFS and register it with SQLite using
-** sqlite3_vfs_register(). If the asynchronous VFS is already initialized
-** and registered, this function is a no-op. The asynchronous IO VFS
-** is registered as "sqlite3async".
-**
-** The asynchronous IO VFS does not make operating system IO requests
-** directly. Instead, it uses an existing VFS implementation for all
-** required file-system operations. If the first parameter to this function
-** is NULL, then the current default VFS is used for IO. If it is not
-** NULL, then it must be the name of an existing VFS. In other words, the
-** first argument to this function is passed to sqlite3_vfs_find() to
-** locate the VFS to use for all real IO operations. This VFS is known
-** as the "parent VFS".
-**
-** If the second parameter to this function is non-zero, then the
-** asynchronous IO VFS is registered as the default VFS for all SQLite
-** database connections within the process. Otherwise, the asynchronous IO
-** VFS is only used by connections opened using sqlite3_open_v2() that
-** specifically request VFS "sqlite3async".
-**
-** If a parent VFS cannot be located, then SQLITE_ERROR is returned.
-** In the unlikely event that operating system specific initialization
-** fails (win32 systems create the required critical section and event
-** objects within this function), then SQLITE_ERROR is also returned.
-** Finally, if the call to sqlite3_vfs_register() returns an error, then
-** the error code is returned to the user by this function. In all three
-** of these cases, intialization has failed and the asynchronous IO VFS
-** is not registered with SQLite.
-**
-** Otherwise, if no error occurs, SQLITE_OK is returned.
-*/
-int sqlite3async_initialize(const char *zParent, int isDefault);
-
-/*
-** This function unregisters the asynchronous IO VFS using
-** sqlite3_vfs_unregister().
-**
-** On win32 platforms, this function also releases the small number of
-** critical section and event objects created by sqlite3async_initialize().
-*/
-void sqlite3async_shutdown(void);
-
-/*
-** This function may only be called when the asynchronous IO VFS is
-** installed (after a call to sqlite3async_initialize()). It processes
-** zero or more queued write operations before returning. It is expected
-** (but not required) that this function will be called by a different
-** thread than those threads that use SQLite. The "background thread"
-** that performs IO.
-**
-** How many queued write operations are performed before returning
-** depends on the global setting configured by passing the SQLITEASYNC_HALT
-** verb to sqlite3async_control() (see below for details). By default
-** this function never returns - it processes all pending operations and
-** then blocks waiting for new ones.
-**
-** If multiple simultaneous calls are made to sqlite3async_run() from two
-** or more threads, then the calls are serialized internally.
-*/
-void sqlite3async_run(void);
-
-/*
-** This function may only be called when the asynchronous IO VFS is
-** installed (after a call to sqlite3async_initialize()). It is used
-** to query or configure various parameters that affect the operation
-** of the asynchronous IO VFS. At present there are three parameters
-** supported:
-**
-** * The "halt" parameter, which configures the circumstances under
-** which the sqlite3async_run() parameter is configured.
-**
-** * The "delay" parameter. Setting the delay parameter to a non-zero
-** value causes the sqlite3async_run() function to sleep for the
-** configured number of milliseconds between each queued write
-** operation.
-**
-** * The "lockfiles" parameter. This parameter determines whether or
-** not the asynchronous IO VFS locks the database files it operates
-** on. Disabling file locking can improve throughput.
-**
-** This function is always passed two arguments. When setting the value
-** of a parameter, the first argument must be one of SQLITEASYNC_HALT,
-** SQLITEASYNC_DELAY or SQLITEASYNC_LOCKFILES. The second argument must
-** be passed the new value for the parameter as type "int".
-**
-** When querying the current value of a paramter, the first argument must
-** be one of SQLITEASYNC_GET_HALT, GET_DELAY or GET_LOCKFILES. The second
-** argument to this function must be of type (int *). The current value
-** of the queried parameter is copied to the memory pointed to by the
-** second argument. For example:
-**
-** int eCurrentHalt;
-** int eNewHalt = SQLITEASYNC_HALT_IDLE;
-**
-** sqlite3async_control(SQLITEASYNC_HALT, eNewHalt);
-** sqlite3async_control(SQLITEASYNC_GET_HALT, &eCurrentHalt);
-** assert( eNewHalt==eCurrentHalt );
-**
-** See below for more detail on each configuration parameter.
-**
-** SQLITEASYNC_HALT:
-**
-** This is used to set the value of the "halt" parameter. The second
-** argument must be one of the SQLITEASYNC_HALT_XXX symbols defined
-** below (either NEVER, IDLE and NOW).
-**
-** If the parameter is set to NEVER, then calls to sqlite3async_run()
-** never return. This is the default setting. If the parameter is set
-** to IDLE, then calls to sqlite3async_run() return as soon as the
-** queue of pending write operations is empty. If the parameter is set
-** to NOW, then calls to sqlite3async_run() return as quickly as
-** possible, without processing any pending write requests.
-**
-** If an attempt is made to set this parameter to an integer value other
-** than SQLITEASYNC_HALT_NEVER, IDLE or NOW, then sqlite3async_control()
-** returns SQLITE_MISUSE and the current value of the parameter is not
-** modified.
-**
-** Modifying the "halt" parameter affects calls to sqlite3async_run()
-** made by other threads that are currently in progress.
-**
-** SQLITEASYNC_DELAY:
-**
-** This is used to set the value of the "delay" parameter. If set to
-** a non-zero value, then after completing a pending write request, the
-** sqlite3async_run() function sleeps for the configured number of
-** milliseconds.
-**
-** If an attempt is made to set this parameter to a negative value,
-** sqlite3async_control() returns SQLITE_MISUSE and the current value
-** of the parameter is not modified.
-**
-** Modifying the "delay" parameter affects calls to sqlite3async_run()
-** made by other threads that are currently in progress.
-**
-** SQLITEASYNC_LOCKFILES:
-**
-** This is used to set the value of the "lockfiles" parameter. This
-** parameter must be set to either 0 or 1. If set to 1, then the
-** asynchronous IO VFS uses the xLock() and xUnlock() methods of the
-** parent VFS to lock database files being read and/or written. If
-** the parameter is set to 0, then these locks are omitted.
-**
-** This parameter may only be set when there are no open database
-** connections using the VFS and the queue of pending write requests
-** is empty. Attempting to set it when this is not true, or to set it
-** to a value other than 0 or 1 causes sqlite3async_control() to return
-** SQLITE_MISUSE and the value of the parameter to remain unchanged.
-**
-** If this parameter is set to zero, then it is only safe to access the
-** database via the asynchronous IO VFS from within a single process. If
-** while writing to the database via the asynchronous IO VFS the database
-** is also read or written from within another process, or via another
-** connection that does not use the asynchronous IO VFS within the same
-** process, the results are undefined (and may include crashes or database
-** corruption).
-**
-** Alternatively, if this parameter is set to 1, then it is safe to access
-** the database from multiple connections within multiple processes using
-** either the asynchronous IO VFS or the parent VFS directly.
-*/
-int sqlite3async_control(int op, ...);
-
-/*
-** Values that can be used as the first argument to sqlite3async_control().
-*/
-#define SQLITEASYNC_HALT 1
-#define SQLITEASYNC_GET_HALT 2
-#define SQLITEASYNC_DELAY 3
-#define SQLITEASYNC_GET_DELAY 4
-#define SQLITEASYNC_LOCKFILES 5
-#define SQLITEASYNC_GET_LOCKFILES 6
-
-/*
-** If the first argument to sqlite3async_control() is SQLITEASYNC_HALT,
-** the second argument should be one of the following.
-*/
-#define SQLITEASYNC_HALT_NEVER 0 /* Never halt (default value) */
-#define SQLITEASYNC_HALT_NOW 1 /* Halt as soon as possible */
-#define SQLITEASYNC_HALT_IDLE 2 /* Halt when write-queue is empty */
-
-#ifdef __cplusplus
-} /* End of the 'extern "C"' block */
-#endif
-#endif /* ifndef __SQLITEASYNC_H_ */
diff --git a/ext/consio/console_io.c b/ext/consio/console_io.c
deleted file mode 100755
index 6b412feef2..0000000000
--- a/ext/consio/console_io.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
-** 2023 November 4
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-********************************************************************************
-** This file implements various interfaces used for console and stream I/O
-** by the SQLite project command-line tools, as explained in console_io.h .
-** Functions prefixed by "SQLITE_INTERNAL_LINKAGE" behave as described there.
-*/
-
-#ifndef SQLITE_CDECL
-# define SQLITE_CDECL
-#endif
-
-#ifndef SHELL_NO_SYSINC
-# include
-# include
-# include
-# include
-# include
-# include "console_io.h"
-# include "sqlite3.h"
-#endif
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-# if (defined(_WIN32) || defined(WIN32)) && !SQLITE_OS_WINRT
-# ifndef SHELL_NO_SYSINC
-# include
-# include
-# undef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# include
-# endif
-# define CIO_WIN_WC_XLATE 1 /* Use WCHAR Windows APIs for console I/O */
-# else
-# ifndef SHELL_NO_SYSINC
-# include
-# endif
-# define CIO_WIN_WC_XLATE 0 /* Use plain C library stream I/O at console */
-# endif
-#else
-# define CIO_WIN_WC_XLATE 0 /* Not exposing translation routines at all */
-#endif
-
-#if CIO_WIN_WC_XLATE
-/* Character used to represent a known-incomplete UTF-8 char group (�) */
-static WCHAR cBadGroup = 0xfffd;
-#endif
-
-#if CIO_WIN_WC_XLATE
-static HANDLE handleOfFile(FILE *pf){
- int fileDesc = _fileno(pf);
- union { intptr_t osfh; HANDLE fh; } fid = {
- (fileDesc>=0)? _get_osfhandle(fileDesc) : (intptr_t)INVALID_HANDLE_VALUE
- };
- return fid.fh;
-}
-#endif
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-typedef struct PerStreamTags {
-# if CIO_WIN_WC_XLATE
- HANDLE hx;
- DWORD consMode;
- char acIncomplete[4];
-# else
- short reachesConsole;
-# endif
- FILE *pf;
-} PerStreamTags;
-
-/* Define NULL-like value for things which can validly be 0. */
-# define SHELL_INVALID_FILE_PTR ((FILE *)~0)
-# if CIO_WIN_WC_XLATE
-# define SHELL_INVALID_CONS_MODE 0xFFFF0000
-# endif
-
-# if CIO_WIN_WC_XLATE
-# define PST_INITIALIZER { INVALID_HANDLE_VALUE, SHELL_INVALID_CONS_MODE, \
- {0,0,0,0}, SHELL_INVALID_FILE_PTR }
-# else
-# define PST_INITIALIZER { 0, SHELL_INVALID_FILE_PTR }
-# endif
-
-/* Quickly say whether a known output is going to the console. */
-# if CIO_WIN_WC_XLATE
-static short pstReachesConsole(PerStreamTags *ppst){
- return (ppst->hx != INVALID_HANDLE_VALUE);
-}
-# else
-# define pstReachesConsole(ppst) 0
-# endif
-
-# if CIO_WIN_WC_XLATE
-static void restoreConsoleArb(PerStreamTags *ppst){
- if( pstReachesConsole(ppst) ) SetConsoleMode(ppst->hx, ppst->consMode);
-}
-# else
-# define restoreConsoleArb(ppst)
-# endif
-
-/* Say whether FILE* appears to be a console, collect associated info. */
-static short streamOfConsole(FILE *pf, /* out */ PerStreamTags *ppst){
-# if CIO_WIN_WC_XLATE
- short rv = 0;
- DWORD dwCM = SHELL_INVALID_CONS_MODE;
- HANDLE fh = handleOfFile(pf);
- ppst->pf = pf;
- if( INVALID_HANDLE_VALUE != fh ){
- rv = (GetFileType(fh) == FILE_TYPE_CHAR && GetConsoleMode(fh,&dwCM));
- }
- ppst->hx = (rv)? fh : INVALID_HANDLE_VALUE;
- ppst->consMode = dwCM;
- return rv;
-# else
- ppst->pf = pf;
- ppst->reachesConsole = ( (short)isatty(fileno(pf)) );
- return ppst->reachesConsole;
-# endif
-}
-
-# if CIO_WIN_WC_XLATE
-/* Define console modes for use with the Windows Console API. */
-# define SHELL_CONI_MODE \
- (ENABLE_ECHO_INPUT | ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | 0x80 \
- | ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_PROCESSED_INPUT)
-# define SHELL_CONO_MODE (ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT \
- | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
-# endif
-
-typedef struct ConsoleInfo {
- PerStreamTags pstSetup[3];
- PerStreamTags pstDesignated[3];
- StreamsAreConsole sacSetup;
-} ConsoleInfo;
-
-static short isValidStreamInfo(PerStreamTags *ppst){
- return (ppst->pf != SHELL_INVALID_FILE_PTR);
-}
-
-static ConsoleInfo consoleInfo = {
- { /* pstSetup */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
- { /* pstDesignated[] */ PST_INITIALIZER, PST_INITIALIZER, PST_INITIALIZER },
- SAC_NoConsole /* sacSetup */
-};
-
-SQLITE_INTERNAL_LINKAGE FILE* invalidFileStream = (FILE *)~0;
-
-# if CIO_WIN_WC_XLATE
-static void maybeSetupAsConsole(PerStreamTags *ppst, short odir){
- if( pstReachesConsole(ppst) ){
- DWORD cm = odir? SHELL_CONO_MODE : SHELL_CONI_MODE;
- SetConsoleMode(ppst->hx, cm);
- }
-}
-# else
-# define maybeSetupAsConsole(ppst,odir)
-# endif
-
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void){
-# if CIO_WIN_WC_XLATE
- int ix = 0;
- while( ix < 6 ){
- PerStreamTags *ppst = (ix<3)?
- &consoleInfo.pstSetup[ix] : &consoleInfo.pstDesignated[ix-3];
- maybeSetupAsConsole(ppst, (ix % 3)>0);
- ++ix;
- }
-# endif
-}
-
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr ){
- StreamsAreConsole rv = SAC_NoConsole;
- FILE* apf[3] = { pfIn, pfOut, pfErr };
- int ix;
- for( ix = 2; ix >= 0; --ix ){
- PerStreamTags *ppst = &consoleInfo.pstSetup[ix];
- if( streamOfConsole(apf[ix], ppst) ){
- rv |= (SAC_InConsole< 0 ) fflush(apf[ix]);
- }
- consoleInfo.sacSetup = rv;
- consoleRenewSetup();
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void ){
-# if CIO_WIN_WC_XLATE
- static ConsoleInfo *pci = &consoleInfo;
- if( pci->sacSetup ){
- int ix;
- for( ix=0; ix<3; ++ix ){
- if( pci->sacSetup & (SAC_InConsole<pstSetup[ix];
- SetConsoleMode(ppst->hx, ppst->consMode);
- }
- }
- }
-# endif
-}
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#ifdef SQLITE_CIO_INPUT_REDIR
-/* Say whether given FILE* is among those known, via either
-** consoleClassifySetup() or set{Output,Error}Stream, as
-** readable, and return an associated PerStreamTags pointer
-** if so. Otherwise, return 0.
-*/
-static PerStreamTags * isKnownReadable(FILE *pf){
- static PerStreamTags *apst[] = {
- &consoleInfo.pstDesignated[0], &consoleInfo.pstSetup[0], 0
- };
- int ix = 0;
- do {
- if( apst[ix]->pf == pf ) break;
- } while( apst[++ix] != 0 );
- return apst[ix];
-}
-#endif
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-/* Say whether given FILE* is among those known, via either
-** consoleClassifySetup() or set{Output,Error}Stream, as
-** writable, and return an associated PerStreamTags pointer
-** if so. Otherwise, return 0.
-*/
-static PerStreamTags * isKnownWritable(FILE *pf){
- static PerStreamTags *apst[] = {
- &consoleInfo.pstDesignated[1], &consoleInfo.pstDesignated[2],
- &consoleInfo.pstSetup[1], &consoleInfo.pstSetup[2], 0
- };
- int ix = 0;
- do {
- if( apst[ix]->pf == pf ) break;
- } while( apst[++ix] != 0 );
- return apst[ix];
-}
-
-static FILE *designateEmitStream(FILE *pf, unsigned chix){
- FILE *rv = consoleInfo.pstDesignated[chix].pf;
- if( pf == invalidFileStream ) return rv;
- else{
- /* Setting a possibly new output stream. */
- PerStreamTags *ppst = isKnownWritable(pf);
- if( ppst != 0 ){
- PerStreamTags pst = *ppst;
- consoleInfo.pstDesignated[chix] = pst;
- }else streamOfConsole(pf, &consoleInfo.pstDesignated[chix]);
- }
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf){
- return designateEmitStream(pf, 1);
-}
-# ifdef CONSIO_SET_ERROR_STREAM
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf){
- return designateEmitStream(pf, 2);
-}
-# endif
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#ifndef SQLITE_CIO_NO_SETMODE
-# if CIO_WIN_WC_XLATE
-static void setModeFlushQ(FILE *pf, short bFlush, int mode){
- if( bFlush ) fflush(pf);
- _setmode(_fileno(pf), mode);
-}
-# else
-# define setModeFlushQ(f, b, m) if(b) fflush(f)
-# endif
-
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *pf, short bFlush){
- setModeFlushQ(pf, bFlush, _O_BINARY);
-}
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *pf, short bFlush){
- setModeFlushQ(pf, bFlush, _O_TEXT);
-}
-# undef setModeFlushQ
-
-#else /* defined(SQLITE_CIO_NO_SETMODE) */
-# define setBinaryMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
-# define setTextMode(f, bFlush) do{ if((bFlush)) fflush(f); }while(0)
-#endif /* defined(SQLITE_CIO_NO_SETMODE) */
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-# if CIO_WIN_WC_XLATE
-/* Write buffer cBuf as output to stream known to reach console,
-** limited to ncTake char's. Return ncTake on success, else 0. */
-static int conZstrEmit(PerStreamTags *ppst, const char *z, int ncTake){
- int rv = 0;
- if( z!=NULL ){
- int nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, 0,0);
- if( nwc > 0 ){
- WCHAR *zw = sqlite3_malloc64(nwc*sizeof(WCHAR));
- if( zw!=NULL ){
- nwc = MultiByteToWideChar(CP_UTF8,0, z,ncTake, zw,nwc);
- if( nwc > 0 ){
- /* Translation from UTF-8 to UTF-16, then WCHARs out. */
- if( WriteConsoleW(ppst->hx, zw,nwc, 0, NULL) ){
- rv = ncTake;
- }
- }
- sqlite3_free(zw);
- }
- }
- }
- return rv;
-}
-
-/* For {f,o,e}PrintfUtf8() when stream is known to reach console. */
-static int conioVmPrintf(PerStreamTags *ppst, const char *zFormat, va_list ap){
- char *z = sqlite3_vmprintf(zFormat, ap);
- if( z ){
- int rv = conZstrEmit(ppst, z, (int)strlen(z));
- sqlite3_free(z);
- return rv;
- }else return 0;
-}
-# endif /* CIO_WIN_WC_XLATE */
-
-# ifdef CONSIO_GET_EMIT_STREAM
-static PerStreamTags * getDesignatedEmitStream(FILE *pf, unsigned chix,
- PerStreamTags *ppst){
- PerStreamTags *rv = isKnownWritable(pf);
- short isValid = (rv!=0)? isValidStreamInfo(rv) : 0;
- if( rv != 0 && isValid ) return rv;
- streamOfConsole(pf, ppst);
- return ppst;
-}
-# endif
-
-/* Get stream info, either for designated output or error stream when
-** chix equals 1 or 2, or for an arbitrary stream when chix == 0.
-** In either case, ppst references a caller-owned PerStreamTags
-** struct which may be filled in if none of the known writable
-** streams is being held by consoleInfo. The ppf parameter is a
-** byref output when chix!=0 and a byref input when chix==0.
- */
-static PerStreamTags *
-getEmitStreamInfo(unsigned chix, PerStreamTags *ppst,
- /* in/out */ FILE **ppf){
- PerStreamTags *ppstTry;
- FILE *pfEmit;
- if( chix > 0 ){
- ppstTry = &consoleInfo.pstDesignated[chix];
- if( !isValidStreamInfo(ppstTry) ){
- ppstTry = &consoleInfo.pstSetup[chix];
- pfEmit = ppst->pf;
- }else pfEmit = ppstTry->pf;
- if( !isValidStreamInfo(ppstTry) ){
- pfEmit = (chix > 1)? stderr : stdout;
- ppstTry = ppst;
- streamOfConsole(pfEmit, ppstTry);
- }
- *ppf = pfEmit;
- }else{
- ppstTry = isKnownWritable(*ppf);
- if( ppstTry != 0 ) return ppstTry;
- streamOfConsole(*ppf, ppst);
- return ppst;
- }
- return ppstTry;
-}
-
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...){
- va_list ap;
- int rv;
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- rv = conioVmPrintf(ppst, zFormat, ap);
- }else{
-# endif
- rv = vfprintf(pfOut, zFormat, ap);
-# if CIO_WIN_WC_XLATE
- }
-# endif
- va_end(ap);
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...){
- va_list ap;
- int rv;
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# else
- getEmitStreamInfo(2, &pst, &pfErr);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- rv = conioVmPrintf(ppst, zFormat, ap);
- }else{
-# endif
- rv = vfprintf(pfErr, zFormat, ap);
-# if CIO_WIN_WC_XLATE
- }
-# endif
- va_end(ap);
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...){
- va_list ap;
- int rv;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
-# else
- getEmitStreamInfo(0, &pst, &pfO);
-# endif
- assert(zFormat!=0);
- va_start(ap, zFormat);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- maybeSetupAsConsole(ppst, 1);
- rv = conioVmPrintf(ppst, zFormat, ap);
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
- }else{
-# endif
- rv = vfprintf(pfO, zFormat, ap);
-# if CIO_WIN_WC_XLATE
- }
-# endif
- va_end(ap);
- return rv;
-}
-
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO){
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
-# else
- getEmitStreamInfo(0, &pst, &pfO);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- int rv;
- maybeSetupAsConsole(ppst, 1);
- rv = conZstrEmit(ppst, z, (int)strlen(z));
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
- return rv;
- }else {
-# endif
- return (fputs(z, pfO)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z){
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# else
- getEmitStreamInfo(2, &pst, &pfErr);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
- else {
-# endif
- return (fputs(z, pfErr)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z){
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
- assert(z!=0);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ) return conZstrEmit(ppst, z, (int)strlen(z));
- else {
-# endif
- return (fputs(z, pfOut)<0)? 0 : (int)strlen(z);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN) && defined(SQLITE_CIO_NO_TRANSLATE))
-/* Skip over as much z[] input char sequence as is valid UTF-8,
-** limited per nAccept char's or whole characters and containing
-** no char cn such that ((1<=0 => char count, nAccept<0 => character
- */
-SQLITE_INTERNAL_LINKAGE const char*
-zSkipValidUtf8(const char *z, int nAccept, long ccm){
- int ng = (nAccept<0)? -nAccept : 0;
- const char *pcLimit = (nAccept>=0)? z+nAccept : 0;
- assert(z!=0);
- while( (pcLimit)? (z= pcLimit ) return z;
- else{
- char ct = *zt++;
- if( ct==0 || (zt-z)>4 || (ct & 0xC0)!=0x80 ){
- /* Trailing bytes are too few, too many, or invalid. */
- return z;
- }
- }
- } while( ((c <<= 1) & 0x40) == 0x40 ); /* Eat lead byte's count. */
- z = zt;
- }
- }
- return z;
-}
-#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-
-#ifdef CONSIO_SPUTB
-SQLITE_INTERNAL_LINKAGE int
-fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
- assert(pfO!=0);
-# if CIO_WIN_WC_XLATE
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
- PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
- if( pstReachesConsole(ppst) ){
- int rv;
- maybeSetupAsConsole(ppst, 1);
- rv = conZstrEmit(ppst, cBuf, nAccept);
- if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
- return rv;
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfO);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-#endif /* defined(CONSIO_SPUTB) */
-
-SQLITE_INTERNAL_LINKAGE int
-oPutbUtf8(const char *cBuf, int nAccept){
- FILE *pfOut;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
-# if CIO_WIN_WC_XLATE
- PerStreamTags *ppst = getEmitStreamInfo(1, &pst, &pfOut);
-# else
- getEmitStreamInfo(1, &pst, &pfOut);
-# endif
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- return conZstrEmit(ppst, cBuf, nAccept);
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfOut);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-
-# ifdef CONSIO_EPUTB
-SQLITE_INTERNAL_LINKAGE int
-ePutbUtf8(const char *cBuf, int nAccept){
- FILE *pfErr;
- PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
- PerStreamTags *ppst = getEmitStreamInfo(2, &pst, &pfErr);
-# if CIO_WIN_WC_XLATE
- if( pstReachesConsole(ppst) ){
- return conZstrEmit(ppst, cBuf, nAccept);
- }else {
-# endif
- return (int)fwrite(cBuf, 1, nAccept, pfErr);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-# endif /* defined(CONSIO_EPUTB) */
-
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn){
- if( pfIn==0 ) pfIn = stdin;
-# if CIO_WIN_WC_XLATE
- if( pfIn == consoleInfo.pstSetup[0].pf
- && (consoleInfo.sacSetup & SAC_InConsole)!=0 ){
-# if CIO_WIN_WC_XLATE==1
-# define SHELL_GULP 150 /* Count of WCHARS to be gulped at a time */
- WCHAR wcBuf[SHELL_GULP+1];
- int lend = 0, noc = 0;
- if( ncMax > 0 ) cBuf[0] = 0;
- while( noc < ncMax-8-1 && !lend ){
- /* There is room for at least 2 more characters and a 0-terminator. */
- int na = (ncMax > SHELL_GULP*4+1 + noc)? SHELL_GULP : (ncMax-1 - noc)/4;
-# undef SHELL_GULP
- DWORD nbr = 0;
- BOOL bRC = ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf, na, &nbr, 0);
- if( bRC && nbr>0 && (wcBuf[nbr-1]&0xF800)==0xD800 ){
- /* Last WHAR read is first of a UTF-16 surrogate pair. Grab its mate. */
- DWORD nbrx;
- bRC &= ReadConsoleW(consoleInfo.pstSetup[0].hx, wcBuf+nbr, 1, &nbrx, 0);
- if( bRC ) nbr += nbrx;
- }
- if( !bRC || (noc==0 && nbr==0) ) return 0;
- if( nbr > 0 ){
- int nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,0,0,0,0);
- if( nmb != 0 && noc+nmb <= ncMax ){
- int iseg = noc;
- nmb = WideCharToMultiByte(CP_UTF8, 0, wcBuf,nbr,cBuf+noc,nmb,0,0);
- noc += nmb;
- /* Fixup line-ends as coded by Windows for CR (or "Enter".)
- ** This is done without regard for any setMode{Text,Binary}()
- ** call that might have been done on the interactive input.
- */
- if( noc > 0 ){
- if( cBuf[noc-1]=='\n' ){
- lend = 1;
- if( noc > 1 && cBuf[noc-2]=='\r' ) cBuf[--noc-1] = '\n';
- }
- }
- /* Check for ^Z (anywhere in line) too, to act as EOF. */
- while( iseg < noc ){
- if( cBuf[iseg]=='\x1a' ){
- noc = iseg; /* Chop ^Z and anything following. */
- lend = 1; /* Counts as end of line too. */
- break;
- }
- ++iseg;
- }
- }else break; /* Drop apparent garbage in. (Could assert.) */
- }else break;
- }
- /* If got nothing, (after ^Z chop), must be at end-of-file. */
- if( noc > 0 ){
- cBuf[noc] = 0;
- return cBuf;
- }else return 0;
-# endif
- }else{
-# endif
- return fgets(cBuf, ncMax, pfIn);
-# if CIO_WIN_WC_XLATE
- }
-# endif
-}
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#undef SHELL_INVALID_FILE_PTR
diff --git a/ext/consio/console_io.h b/ext/consio/console_io.h
deleted file mode 100644
index 21697d595e..0000000000
--- a/ext/consio/console_io.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
-** 2023 November 1
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-********************************************************************************
-** This file exposes various interfaces used for console and other I/O
-** by the SQLite project command-line tools. These interfaces are used
-** at either source conglomeration time, compilation time, or run time.
-** This source provides for either inclusion into conglomerated,
-** "single-source" forms or separate compilation then linking.
-**
-** Platform dependencies are "hidden" here by various stratagems so
-** that, provided certain conditions are met, the programs using this
-** source or object code compiled from it need no explicit conditional
-** compilation in their source for their console and stream I/O.
-**
-** The symbols and functionality exposed here are not a public API.
-** This code may change in tandem with other project code as needed.
-**
-** When this .h file and its companion .c are directly incorporated into
-** a source conglomeration (such as shell.c), the preprocessor symbol
-** CIO_WIN_WC_XLATE is defined as 0 or 1, reflecting whether console I/O
-** translation for Windows is effected for the build.
-*/
-
-#ifndef SQLITE_INTERNAL_LINKAGE
-# define SQLITE_INTERNAL_LINKAGE extern /* external to translation unit */
-# include
-#else
-# define SHELL_NO_SYSINC /* Better yet, modify mkshellc.tcl for this. */
-#endif
-
-#ifndef SQLITE3_H
-# include "sqlite3.h"
-#endif
-
-#ifndef SQLITE_CIO_NO_CLASSIFY
-
-/* Define enum for use with following function. */
-typedef enum StreamsAreConsole {
- SAC_NoConsole = 0,
- SAC_InConsole = 1, SAC_OutConsole = 2, SAC_ErrConsole = 4,
- SAC_AnyConsole = 0x7
-} StreamsAreConsole;
-
-/*
-** Classify the three standard I/O streams according to whether
-** they are connected to a console attached to the process.
-**
-** Returns the bit-wise OR of SAC_{In,Out,Err}Console values,
-** or SAC_NoConsole if none of the streams reaches a console.
-**
-** This function should be called before any I/O is done with
-** the given streams. As a side-effect, the given inputs are
-** recorded so that later I/O operations on them may be done
-** differently than the C library FILE* I/O would be done,
-** iff the stream is used for the I/O functions that follow,
-** and to support the ones that use an implicit stream.
-**
-** On some platforms, stream or console mode alteration (aka
-** "Setup") may be made which is undone by consoleRestore().
-*/
-SQLITE_INTERNAL_LINKAGE StreamsAreConsole
-consoleClassifySetup( FILE *pfIn, FILE *pfOut, FILE *pfErr );
-/* A usual call for convenience: */
-#define SQLITE_STD_CONSOLE_INIT() consoleClassifySetup(stdin,stdout,stderr)
-
-/*
-** After an initial call to consoleClassifySetup(...), renew
-** the same setup it effected. (A call not after is an error.)
-** This will restore state altered by consoleRestore();
-**
-** Applications which run an inferior (child) process which
-** inherits the same I/O streams may call this function after
-** such a process exits to guard against console mode changes.
-*/
-SQLITE_INTERNAL_LINKAGE void consoleRenewSetup(void);
-
-/*
-** Undo any side-effects left by consoleClassifySetup(...).
-**
-** This should be called after consoleClassifySetup() and
-** before the process terminates normally. It is suitable
-** for use with the atexit() C library procedure. After
-** this call, no console I/O should be done until one of
-** console{Classify or Renew}Setup(...) is called again.
-**
-** Applications which run an inferior (child) process that
-** inherits the same I/O streams might call this procedure
-** before so that said process will have a console setup
-** however users have configured it or come to expect.
-*/
-SQLITE_INTERNAL_LINKAGE void SQLITE_CDECL consoleRestore( void );
-
-#else /* defined(SQLITE_CIO_NO_CLASSIFY) */
-# define consoleClassifySetup(i,o,e)
-# define consoleRenewSetup()
-# define consoleRestore()
-#endif /* defined(SQLITE_CIO_NO_CLASSIFY) */
-
-#ifndef SQLITE_CIO_NO_REDIRECT
-/*
-** Set stream to be used for the functions below which write
-** to "the designated X stream", where X is Output or Error.
-** Returns the previous value.
-**
-** Alternatively, pass the special value, invalidFileStream,
-** to get the designated stream value without setting it.
-**
-** Before the designated streams are set, they default to
-** those passed to consoleClassifySetup(...), and before
-** that is called they default to stdout and stderr.
-**
-** It is error to close a stream so designated, then, without
-** designating another, use the corresponding {o,e}Emit(...).
-*/
-SQLITE_INTERNAL_LINKAGE FILE *invalidFileStream;
-SQLITE_INTERNAL_LINKAGE FILE *setOutputStream(FILE *pf);
-# ifdef CONSIO_SET_ERROR_STREAM
-SQLITE_INTERNAL_LINKAGE FILE *setErrorStream(FILE *pf);
-# endif
-#else
-# define setOutputStream(pf)
-# define setErrorStream(pf)
-#endif /* !defined(SQLITE_CIO_NO_REDIRECT) */
-
-#ifndef SQLITE_CIO_NO_TRANSLATE
-/*
-** Emit output like fprintf(). If the output is going to the
-** console and translation from UTF-8 is necessary, perform
-** the needed translation. Otherwise, write formatted output
-** to the provided stream almost as-is, possibly with newline
-** translation as specified by set{Binary,Text}Mode().
-*/
-SQLITE_INTERNAL_LINKAGE int fPrintfUtf8(FILE *pfO, const char *zFormat, ...);
-/* Like fPrintfUtf8 except stream is always the designated output. */
-SQLITE_INTERNAL_LINKAGE int oPrintfUtf8(const char *zFormat, ...);
-/* Like fPrintfUtf8 except stream is always the designated error. */
-SQLITE_INTERNAL_LINKAGE int ePrintfUtf8(const char *zFormat, ...);
-
-/*
-** Emit output like fputs(). If the output is going to the
-** console and translation from UTF-8 is necessary, perform
-** the needed translation. Otherwise, write given text to the
-** provided stream almost as-is, possibly with newline
-** translation as specified by set{Binary,Text}Mode().
-*/
-SQLITE_INTERNAL_LINKAGE int fPutsUtf8(const char *z, FILE *pfO);
-/* Like fPutsUtf8 except stream is always the designated output. */
-SQLITE_INTERNAL_LINKAGE int oPutsUtf8(const char *z);
-/* Like fPutsUtf8 except stream is always the designated error. */
-SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
-
-/*
-** Emit output like fPutsUtf8(), except that the length of the
-** accepted char or character sequence is limited by nAccept.
-**
-** Returns the number of accepted char values.
-*/
-#ifdef CONSIO_SPUTB
-SQLITE_INTERNAL_LINKAGE int
-fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
-#endif
-/* Like fPutbUtf8 except stream is always the designated output. */
-SQLITE_INTERNAL_LINKAGE int
-oPutbUtf8(const char *cBuf, int nAccept);
-/* Like fPutbUtf8 except stream is always the designated error. */
-#ifdef CONSIO_EPUTB
-SQLITE_INTERNAL_LINKAGE int
-ePutbUtf8(const char *cBuf, int nAccept);
-#endif
-
-/*
-** Collect input like fgets(...) with special provisions for input
-** from the console on platforms that require same. Defers to the
-** C library fgets() when input is not from the console. Newline
-** translation may be done as set by set{Binary,Text}Mode(). As a
-** convenience, pfIn==NULL is treated as stdin.
-*/
-SQLITE_INTERNAL_LINKAGE char* fGetsUtf8(char *cBuf, int ncMax, FILE *pfIn);
-/* Like fGetsUtf8 except stream is always the designated input. */
-/* SQLITE_INTERNAL_LINKAGE char* iGetsUtf8(char *cBuf, int ncMax); */
-
-#endif /* !defined(SQLITE_CIO_NO_TRANSLATE) */
-
-#ifndef SQLITE_CIO_NO_SETMODE
-/*
-** Set given stream for binary mode, where newline translation is
-** not done, or for text mode where, for some platforms, newlines
-** are translated to the platform's conventional char sequence.
-** If bFlush true, flush the stream.
-**
-** An additional side-effect is that if the stream is one passed
-** to consoleClassifySetup() as an output, it is flushed first.
-**
-** Note that binary/text mode has no effect on console I/O
-** translation. On all platforms, newline to the console starts
-** a new line and CR,LF chars from the console become a newline.
-*/
-SQLITE_INTERNAL_LINKAGE void setBinaryMode(FILE *, short bFlush);
-SQLITE_INTERNAL_LINKAGE void setTextMode(FILE *, short bFlush);
-#endif
-
-#ifdef SQLITE_CIO_PROMPTED_IN
-typedef struct Prompts {
- int numPrompts;
- const char **azPrompts;
-} Prompts;
-
-/*
-** Macros for use of a line editor.
-**
-** The following macros define operations involving use of a
-** line-editing library or simple console interaction.
-** A "T" argument is a text (char *) buffer or filename.
-** A "N" argument is an integer.
-**
-** SHELL_ADD_HISTORY(T) // Record text as line(s) of history.
-** SHELL_READ_HISTORY(T) // Read history from file named by T.
-** SHELL_WRITE_HISTORY(T) // Write history to file named by T.
-** SHELL_STIFLE_HISTORY(N) // Limit history to N entries.
-**
-** A console program which does interactive console input is
-** expected to call:
-** SHELL_READ_HISTORY(T) before collecting such input;
-** SHELL_ADD_HISTORY(T) as record-worthy input is taken;
-** SHELL_STIFLE_HISTORY(N) after console input ceases; then
-** SHELL_WRITE_HISTORY(T) before the program exits.
-*/
-
-/*
-** Retrieve a single line of input text from an input stream.
-**
-** If pfIn is the input stream passed to consoleClassifySetup(),
-** and azPrompt is not NULL, then a prompt is issued before the
-** line is collected, as selected by the isContinuation flag.
-** Array azPrompt[{0,1}] holds the {main,continuation} prompt.
-**
-** If zBufPrior is not NULL then it is a buffer from a prior
-** call to this routine that can be reused, or will be freed.
-**
-** The result is stored in space obtained from malloc() and
-** must either be freed by the caller or else passed back to
-** this function as zBufPrior for reuse.
-**
-** This function may call upon services of a line-editing
-** library to interactively collect line edited input.
-*/
-SQLITE_INTERNAL_LINKAGE char *
-shellGetLine(FILE *pfIn, char *zBufPrior, int nLen,
- short isContinuation, Prompts azPrompt);
-#endif /* defined(SQLITE_CIO_PROMPTED_IN) */
-/*
-** TBD: Define an interface for application(s) to generate
-** completion candidates for use by the line-editor.
-**
-** This may be premature; the CLI is the only application
-** that does this. Yet, getting line-editing melded into
-** console I/O is desirable because a line-editing library
-** may have to establish console operating mode, possibly
-** in a way that interferes with the above functionality.
-*/
-
-#if !(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))
-/* Skip over as much z[] input char sequence as is valid UTF-8,
-** limited per nAccept char's or whole characters and containing
-** no char cn such that ((1<=0 => char count, nAccept<0 => character
- */
-SQLITE_INTERNAL_LINKAGE const char*
-zSkipValidUtf8(const char *z, int nAccept, long ccm);
-
-#endif
diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test
index 453334234d..0c3b512af0 100644
--- a/ext/expert/expert1.test
+++ b/ext/expert/expert1.test
@@ -8,6 +8,7 @@
# May you share freely, never taking more than you give.
#
#***********************************************************************
+# TESTRUNNER: shell
#
# The focus of this file is testing the CLI shell tool. Specifically,
# the ".recommend" command.
@@ -401,6 +402,19 @@ do_setup_rec_test $tn.19.0 {
SCAN t1 USING COVERING INDEX t1_idx_01a7214e
}
+ifcapable fts5 {
+ do_setup_rec_test $tn.20.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a);
+ CREATE TABLE t1(x, y);
+ } {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ SCAN ft VIRTUAL TABLE INDEX 0:
+ SEARCH t1 USING INDEX t1_idx_00000078 (x=?)
+ }
+}
+
}
proc do_candidates_test {tn sql res} {
@@ -427,6 +441,8 @@ do_execsql_test 5.0 {
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
+
+ CREATE INDEX i1 ON t1( lower(a) );
}
do_candidates_test 5.1 {
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
@@ -456,6 +472,7 @@ do_execsql_test 5.3 {
ANALYZE;
SELECT * FROM sqlite_stat1 ORDER BY 1, 2;
} {
+ t1 i1 {100 50}
t1 t1_idx_00000061 {100 50}
t1 t1_idx_00000062 {100 20}
t1 t1_idx_000123a7 {100 50 17}
@@ -464,6 +481,13 @@ do_execsql_test 5.3 {
t2 t2_idx_0001295b {100 20 5}
}
+do_catchsql_test 5.4 {
+ SELECT sqlite_expert_rem(123, 123);
+} {1 {no such function: sqlite_expert_rem}}
+do_catchsql_test 5.5 {
+ SELECT sqlite_expert_sample();
+} {1 {no such function: sqlite_expert_sample}}
+
if 0 {
do_test expert1-6.0 {
catchcmd :memory: {
@@ -483,4 +507,103 @@ USE TEMP B-TREE FOR ORDER BY
}}
}
+do_execsql_test 6.0 {
+ CREATE TABLE x1(a, b, c, d);
+ CREATE INDEX x1ab ON x1(a, lower(b));
+ CREATE INDEX x1dcba ON x1(d, b+c, a);
+}
+
+do_candidates_test 6.1 {
+ SELECT * FROM x1 WHERE b=? ORDER BY a;
+} {
+ CREATE INDEX x1_idx_0001267f ON x1(b, a);
+ CREATE INDEX x1_idx_00000062 ON x1(b);
+}
+
+#-------------------------------------------------------------------------
+ifcapable fts5 {
+ reset_db
+ do_execsql_test 7.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a);
+ CREATE TABLE t1(x, y);
+ }
+
+ do_candidates_test 7.1 {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ }
+
+ register_tcl_module db
+ proc vtab_command {method args} {
+ global G
+
+ switch -- $method {
+ xConnect {
+ return "CREATE TABLE t1(a, b, c);"
+ }
+
+ xBestIndex {
+ return [list]
+ }
+
+ xFilter {
+ return [list sql "SELECT rowid, * FROM t0"]
+ }
+ }
+
+ return {}
+ }
+
+ do_execsql_test 7.2 {
+ CREATE TABLE t0(a, b, c);
+ INSERT INTO t0 VALUES(1, 2, 3), (11, 22, 33);
+ CREATE VIRTUAL TABLE t2 USING tcl(vtab_command);
+ }
+
+ do_execsql_test 7.3 {
+ SELECT * FROM t2
+ } {
+ 1 2 3
+ 11 22 33
+ }
+
+ do_candidates_test 7.4 {
+ SELECT * FROM ft, t1 WHERE a=x
+ } {
+ CREATE INDEX t1_idx_00000078 ON t1(x);
+ }
+
+ do_test 7.5 {
+ set expert [sqlite3_expert_new db]
+ list [catch { $expert sql "SELECT * FROM ft, t2 WHERE b=1" } msg] $msg
+ } {1 {no such table: t2}}
+ $expert destroy
+
+ reset_db
+ do_execsql_test 7.6 {
+ BEGIN TRANSACTION;
+ CREATE TABLE IF NOT EXISTS 'bfts_idx_data'(id INTEGER PRIMARY KEY, block BLOB);
+ CREATE TABLE IF NOT EXISTS 'fts_idx_data'(id INTEGER PRIMARY KEY, block BLOB);
+ INSERT INTO fts_idx_data VALUES(1,X'');
+ INSERT INTO fts_idx_data VALUES(10,X'00000000ff000001000000');
+ CREATE TABLE IF NOT EXISTS 'fts_idx_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
+ CREATE TABLE IF NOT EXISTS 'fts_idx_docsize'(id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER);
+ CREATE TABLE IF NOT EXISTS 'fts_idx_config'(k PRIMARY KEY, v) WITHOUT ROWID;
+ INSERT INTO fts_idx_config VALUES('version',4);
+ PRAGMA writable_schema=ON;
+ INSERT INTO sqlite_schema(type,name,tbl_name,rootpage,sql)VALUES('table','fts_idx','fts_idx',0,'CREATE VIRTUAL TABLE fts_idx USING fts5(Title, Description, Channel, Tags, content='''', contentless_delete=1)');
+
+ CREATE TABLE f(x BLOB, y);
+ COMMIT;
+ PRAGMA writable_schema = RESET;
+ }
+
+ do_candidates_test 7.4 {
+ SELECT * FROM fts_idx, f WHERE x = fts_idx.Channel
+ } {
+ CREATE INDEX f_idx_00000078 ON f(x);
+ }
+}
+
finish_test
diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c
index 33d62226f0..93693cfae9 100644
--- a/ext/expert/sqlite3expert.c
+++ b/ext/expert/sqlite3expert.c
@@ -626,7 +626,7 @@ static int expertFilter(
pCsr->pData = 0;
if( rc==SQLITE_OK ){
rc = idxPrintfPrepareStmt(pExpert->db, &pCsr->pData, &pVtab->base.zErrMsg,
- "SELECT * FROM main.%Q WHERE sample()", pVtab->pTab->zName
+ "SELECT * FROM main.%Q WHERE sqlite_expert_sample()", pVtab->pTab->zName
);
}
@@ -1392,6 +1392,66 @@ static int idxProcessTriggers(sqlite3expert *p, char **pzErr){
return rc;
}
+/*
+** This function tests if the schema of the main database of database handle
+** db contains an object named zTab. Assuming no error occurs, output parameter
+** (*pbContains) is set to true if zTab exists, or false if it does not.
+**
+** Or, if an error occurs, an SQLite error code is returned. The final value
+** of (*pbContains) is undefined in this case.
+*/
+static int expertDbContainsObject(
+ sqlite3 *db,
+ const char *zTab,
+ int *pbContains /* OUT: True if object exists */
+){
+ const char *zSql = "SELECT 1 FROM sqlite_schema WHERE name = ?";
+ sqlite3_stmt *pSql = 0;
+ int rc = SQLITE_OK;
+ int ret = 0;
+
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pSql, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pSql, 1, zTab, -1, SQLITE_STATIC);
+ if( SQLITE_ROW==sqlite3_step(pSql) ){
+ ret = 1;
+ }
+ rc = sqlite3_finalize(pSql);
+ }
+
+ *pbContains = ret;
+ return rc;
+}
+
+/*
+** Execute SQL command zSql using database handle db. If no error occurs,
+** set (*pzErr) to NULL and return SQLITE_OK.
+**
+** If an error does occur, return an SQLite error code and set (*pzErr) to
+** point to a buffer containing an English language error message. Except,
+** if the error message begins with "no such module:", then ignore the
+** error and return as if the SQL statement had succeeded.
+**
+** This is used to copy as much of the database schema as possible while
+** ignoring any errors related to missing virtual table modules.
+*/
+static int expertSchemaSql(sqlite3 *db, const char *zSql, char **pzErr){
+ int rc = SQLITE_OK;
+ char *zErr = 0;
+
+ rc = sqlite3_exec(db, zSql, 0, 0, &zErr);
+ if( rc!=SQLITE_OK && zErr ){
+ int nErr = STRLEN(zErr);
+ if( nErr>=15 && memcmp(zErr, "no such module:", 15)==0 ){
+ sqlite3_free(zErr);
+ rc = SQLITE_OK;
+ zErr = 0;
+ }
+ }
+
+ *pzErr = zErr;
+ return rc;
+}
static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
int rc = idxRegisterVtab(p);
@@ -1403,26 +1463,35 @@ static int idxCreateVtabSchema(sqlite3expert *p, char **pzErrmsg){
** 2) Create the equivalent virtual table in dbv.
*/
rc = idxPrepareStmt(p->db, &pSchema, pzErrmsg,
- "SELECT type, name, sql, 1 FROM sqlite_schema "
- "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%%' "
+ "SELECT type, name, sql, 1, "
+ " substr(sql,1,14)=='create virtual' COLLATE nocase "
+ "FROM sqlite_schema "
+ "WHERE type IN ('table','view') AND "
+ " substr(name,1,7)!='sqlite_' COLLATE nocase "
" UNION ALL "
- "SELECT type, name, sql, 2 FROM sqlite_schema "
+ "SELECT type, name, sql, 2, 0 FROM sqlite_schema "
"WHERE type = 'trigger'"
" AND tbl_name IN(SELECT name FROM sqlite_schema WHERE type = 'view') "
- "ORDER BY 4, 1"
+ "ORDER BY 4, 5 DESC, 1"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSchema) ){
const char *zType = (const char*)sqlite3_column_text(pSchema, 0);
const char *zName = (const char*)sqlite3_column_text(pSchema, 1);
const char *zSql = (const char*)sqlite3_column_text(pSchema, 2);
+ int bVirtual = sqlite3_column_int(pSchema, 4);
+ int bExists = 0;
if( zType==0 || zName==0 ) continue;
- if( zType[0]=='v' || zType[1]=='r' ){
- if( zSql ) rc = sqlite3_exec(p->dbv, zSql, 0, 0, pzErrmsg);
+ rc = expertDbContainsObject(p->dbv, zName, &bExists);
+ if( rc || bExists ) continue;
+
+ if( zType[0]=='v' || zType[1]=='r' || bVirtual ){
+ /* A view. Or a trigger on a view. */
+ if( zSql ) rc = expertSchemaSql(p->dbv, zSql, pzErrmsg);
}else{
IdxTable *pTab;
rc = idxGetTableInfo(p->db, zName, &pTab, pzErrmsg);
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pTab!=0) ){
int i;
char *zInner = 0;
char *zOuter = 0;
@@ -1500,7 +1569,7 @@ struct IdxRemCtx {
};
/*
-** Implementation of scalar function rem().
+** Implementation of scalar function sqlite_expert_rem().
*/
static void idxRemFunc(
sqlite3_context *pCtx,
@@ -1513,7 +1582,7 @@ static void idxRemFunc(
assert( argc==2 );
iSlot = sqlite3_value_int(argv[0]);
- assert( iSlot<=p->nSlot );
+ assert( iSlotnSlot );
pSlot = &p->aSlot[iSlot];
switch( pSlot->eType ){
@@ -1623,8 +1692,15 @@ static int idxPopulateOneStat1(
const char *zComma = zCols==0 ? "" : ", ";
const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0);
const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1);
+ if( zName==0 ){
+ /* This index contains an expression. Ignore it. */
+ sqlite3_free(zCols);
+ sqlite3_free(zOrder);
+ return sqlite3_reset(pIndexXInfo);
+ }
zCols = idxAppendText(&rc, zCols,
- "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl
+ "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s",
+ zComma, zName, nCol, zName, zColl
);
zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol);
}
@@ -1757,13 +1833,13 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
if( rc==SQLITE_OK ){
sqlite3 *dbrem = (p->iSample==100 ? p->db : p->dbv);
- rc = sqlite3_create_function(
- dbrem, "rem", 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
+ rc = sqlite3_create_function(dbrem, "sqlite_expert_rem",
+ 2, SQLITE_UTF8, (void*)pCtx, idxRemFunc, 0, 0
);
}
if( rc==SQLITE_OK ){
- rc = sqlite3_create_function(
- p->db, "sample", 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
+ rc = sqlite3_create_function(p->db, "sqlite_expert_sample",
+ 0, SQLITE_UTF8, (void*)&samplectx, idxSampleFunc, 0, 0
);
}
@@ -1815,6 +1891,9 @@ static int idxPopulateStat1(sqlite3expert *p, char **pzErr){
rc = sqlite3_exec(p->dbm, "ANALYZE sqlite_schema", 0, 0, 0);
}
+ sqlite3_create_function(p->db, "sqlite_expert_rem", 2, SQLITE_UTF8, 0,0,0,0);
+ sqlite3_create_function(p->db, "sqlite_expert_sample", 0,SQLITE_UTF8,0,0,0,0);
+
sqlite3_exec(p->db, "DROP TABLE IF EXISTS temp."UNIQUE_TABLE_NAME,0,0,0);
return rc;
}
@@ -1947,12 +2026,18 @@ sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErrmsg){
if( rc==SQLITE_OK ){
sqlite3_stmt *pSql = 0;
rc = idxPrintfPrepareStmt(pNew->db, &pSql, pzErrmsg,
- "SELECT sql FROM sqlite_schema WHERE name NOT LIKE 'sqlite_%%'"
- " AND sql NOT LIKE 'CREATE VIRTUAL %%'"
+ "SELECT sql, name, substr(sql,1,14)=='create virtual' COLLATE nocase"
+ " FROM sqlite_schema WHERE substr(name,1,7)!='sqlite_' COLLATE nocase"
+ " ORDER BY 3 DESC, rowid"
);
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
- if( zSql ) rc = sqlite3_exec(pNew->dbm, zSql, 0, 0, pzErrmsg);
+ const char *zName = (const char*)sqlite3_column_text(pSql, 1);
+ int bExists = 0;
+ rc = expertDbContainsObject(pNew->dbm, zName, &bExists);
+ if( rc==SQLITE_OK && zSql && bExists==0 ){
+ rc = expertSchemaSql(pNew->dbm, zSql, pzErrmsg);
+ }
}
idxFinalize(&rc, pSql);
}
diff --git a/ext/expert/test_expert.c b/ext/expert/test_expert.c
index 064c1908a9..cae5d0f258 100644
--- a/ext/expert/test_expert.c
+++ b/ext/expert/test_expert.c
@@ -16,15 +16,7 @@
#include "sqlite3expert.h"
#include
#include
-
-#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
-#else
-# include "tcl.h"
-# ifndef SQLITE_TCLAPI
-# define SQLITE_TCLAPI
-# endif
-#endif
+#include "tclsqlite.h"
#ifndef SQLITE_OMIT_VIRTUALTABLE
diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c
index 65852804a1..2b2c3b8d26 100644
--- a/ext/fts3/fts3.c
+++ b/ext/fts3/fts3.c
@@ -2344,10 +2344,15 @@ static int fts3PoslistPhraseMerge(
if( *p1==POS_COLUMN ){
p1++;
p1 += fts3GetVarint32(p1, &iCol1);
+ /* iCol1==0 indicates corruption. Column 0 does not have a POS_COLUMN
+ ** entry, so this is actually end-of-doclist. */
+ if( iCol1==0 ) return 0;
}
if( *p2==POS_COLUMN ){
p2++;
p2 += fts3GetVarint32(p2, &iCol2);
+ /* As above, iCol2==0 indicates corruption. */
+ if( iCol2==0 ) return 0;
}
while( 1 ){
@@ -4006,7 +4011,7 @@ static int fts3ShadowName(const char *zName){
** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
** table.
*/
-static int fts3Integrity(
+static int fts3IntegrityMethod(
sqlite3_vtab *pVtab, /* The virtual table to be checked */
const char *zSchema, /* Name of schema in which pVtab lives */
const char *zTabname, /* Name of the pVTab table */
@@ -4014,31 +4019,24 @@ static int fts3Integrity(
char **pzErr /* Write error message here */
){
Fts3Table *p = (Fts3Table*)pVtab;
- char *zSql;
- int rc;
- char *zErr = 0;
+ int rc = SQLITE_OK;
+ int bOk = 0;
- assert( pzErr!=0 );
- assert( *pzErr==0 );
UNUSED_PARAMETER(isQuick);
- zSql = sqlite3_mprintf(
- "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
- zSchema, zTabname, zTabname);
- if( zSql==0 ){
- return SQLITE_NOMEM;
- }
- rc = sqlite3_exec(p->db, zSql, 0, 0, &zErr);
- sqlite3_free(zSql);
- if( (rc&0xff)==SQLITE_CORRUPT ){
- *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
- p->bFts4 ? 4 : 3, zSchema, zTabname);
- }else if( rc!=SQLITE_OK ){
+ rc = sqlite3Fts3IntegrityCheck(p, &bOk);
+ assert( rc!=SQLITE_CORRUPT_VTAB );
+ if( rc==SQLITE_ERROR || (rc&0xFF)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("unable to validate the inverted index for"
" FTS%d table %s.%s: %s",
- p->bFts4 ? 4 : 3, zSchema, zTabname, zErr);
+ p->bFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc));
+ if( *pzErr ) rc = SQLITE_OK;
+ }else if( rc==SQLITE_OK && bOk==0 ){
+ *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname);
+ if( *pzErr==0 ) rc = SQLITE_NOMEM;
}
- sqlite3_free(zErr);
- return SQLITE_OK;
+ sqlite3Fts3SegmentsClose(p);
+ return rc;
}
@@ -4068,7 +4066,7 @@ static const sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
- /* xIntegrity */ fts3Integrity,
+ /* xIntegrity */ fts3IntegrityMethod,
};
/*
@@ -5525,7 +5523,7 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
nTmp += p->pRight->pPhrase->doclist.nList;
}
nTmp += p->pPhrase->doclist.nList;
- aTmp = sqlite3_malloc64(nTmp*2);
+ aTmp = sqlite3_malloc64(nTmp*2 + FTS3_VARINT_MAX);
if( !aTmp ){
*pRc = SQLITE_NOMEM;
res = 0;
@@ -5789,6 +5787,24 @@ static void fts3EvalRestart(
}
}
+/*
+** Expression node pExpr is an MSR phrase. This function restarts pExpr
+** so that it is a regular phrase query, not an MSR. SQLITE_OK is returned
+** if successful, or an SQLite error code otherwise.
+*/
+int sqlite3Fts3MsrCancel(Fts3Cursor *pCsr, Fts3Expr *pExpr){
+ int rc = SQLITE_OK;
+ if( pExpr->bEof==0 ){
+ i64 iDocid = pExpr->iDocid;
+ fts3EvalRestart(pCsr, pExpr, &rc);
+ while( rc==SQLITE_OK && pExpr->iDocid!=iDocid ){
+ fts3EvalNextRow(pCsr, pExpr, &rc);
+ if( pExpr->bEof ) rc = FTS_CORRUPT_VTAB;
+ }
+ }
+ return rc;
+}
+
/*
** After allocating the Fts3Expr.aMI[] array for each phrase in the
** expression rooted at pExpr, the cursor iterates through all rows matched
@@ -6176,7 +6192,7 @@ int sqlite3Fts3Corrupt(){
}
#endif
-#if !SQLITE_CORE
+#if !defined(SQLITE_CORE)
/*
** Initialize API pointer table, if required.
*/
diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h
index 5a5b123b4c..77e6737af4 100644
--- a/ext/fts3/fts3Int.h
+++ b/ext/fts3/fts3Int.h
@@ -640,6 +640,7 @@ int sqlite3Fts3MsrIncrNext(
int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
+int sqlite3Fts3MsrCancel(Fts3Cursor*, Fts3Expr*);
/* fts3_tokenize_vtab.c */
int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
@@ -653,5 +654,7 @@ int sqlite3FtsUnicodeIsdiacritic(int);
int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
+int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
+
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
diff --git a/ext/fts3/fts3_expr.c b/ext/fts3/fts3_expr.c
index ea8167c595..9e201b1684 100644
--- a/ext/fts3/fts3_expr.c
+++ b/ext/fts3/fts3_expr.c
@@ -319,10 +319,11 @@ static int getNextString(
Fts3PhraseToken *pToken;
p = fts3ReallocOrFree(p, nSpace + ii*sizeof(Fts3PhraseToken));
- if( !p ) goto no_mem;
-
zTemp = fts3ReallocOrFree(zTemp, nTemp + nByte);
- if( !zTemp ) goto no_mem;
+ if( !zTemp || !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
assert( nToken==ii );
pToken = &((Fts3Phrase *)(&p[1]))->aToken[ii];
@@ -337,9 +338,6 @@ static int getNextString(
nToken = ii+1;
}
}
-
- pModule->xClose(pCursor);
- pCursor = 0;
}
if( rc==SQLITE_DONE ){
@@ -347,7 +345,10 @@ static int getNextString(
char *zBuf = 0;
p = fts3ReallocOrFree(p, nSpace + nToken*sizeof(Fts3PhraseToken) + nTemp);
- if( !p ) goto no_mem;
+ if( !p ){
+ rc = SQLITE_NOMEM;
+ goto getnextstring_out;
+ }
memset(p, 0, (char *)&(((Fts3Phrase *)&p[1])->aToken[0])-(char *)p);
p->eType = FTSQUERY_PHRASE;
p->pPhrase = (Fts3Phrase *)&p[1];
@@ -355,11 +356,9 @@ static int getNextString(
p->pPhrase->nToken = nToken;
zBuf = (char *)&p->pPhrase->aToken[nToken];
+ assert( nTemp==0 || zTemp );
if( zTemp ){
memcpy(zBuf, zTemp, nTemp);
- sqlite3_free(zTemp);
- }else{
- assert( nTemp==0 );
}
for(jj=0; jjpPhrase->nToken; jj++){
@@ -369,17 +368,17 @@ static int getNextString(
rc = SQLITE_OK;
}
- *ppExpr = p;
- return rc;
-no_mem:
-
+ getnextstring_out:
if( pCursor ){
pModule->xClose(pCursor);
}
sqlite3_free(zTemp);
- sqlite3_free(p);
- *ppExpr = 0;
- return SQLITE_NOMEM;
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(p);
+ p = 0;
+ }
+ *ppExpr = p;
+ return rc;
}
/*
diff --git a/ext/fts3/fts3_snippet.c b/ext/fts3/fts3_snippet.c
index 227c5f00f6..8a6ab8ea62 100644
--- a/ext/fts3/fts3_snippet.c
+++ b/ext/fts3/fts3_snippet.c
@@ -398,6 +398,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
return 1;
}
+ assert( pIter->nSnippet>=0 );
pIter->iCurrent = iStart = iEnd - pIter->nSnippet + 1;
for(i=0; inPhrase; i++){
SnippetPhrase *pPhrase = &pIter->aPhrase[i];
@@ -446,7 +447,7 @@ static void fts3SnippetDetails(
}
mCover |= mPhrase;
- for(j=0; jnToken; j++){
+ for(j=0; jnToken && jnSnippet; j++){
mHighlight |= (mPos>>j);
}
@@ -1585,6 +1586,22 @@ static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
return rc;
}
+/*
+** If expression pExpr is a phrase expression that uses an MSR query,
+** restart it as a regular, non-incremental query. Return SQLITE_OK
+** if successful, or an SQLite error code otherwise.
+*/
+static int fts3ExprRestartIfCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
+ TermOffsetCtx *p = (TermOffsetCtx*)ctx;
+ int rc = SQLITE_OK;
+ UNUSED_PARAMETER(iPhrase);
+ if( pExpr->pPhrase && pExpr->pPhrase->bIncr ){
+ rc = sqlite3Fts3MsrCancel(p->pCsr, pExpr);
+ pExpr->pPhrase->bIncr = 0;
+ }
+ return rc;
+}
+
/*
** Implementation of offsets() function.
*/
@@ -1621,6 +1638,12 @@ void sqlite3Fts3Offsets(
sCtx.iDocid = pCsr->iPrevId;
sCtx.pCsr = pCsr;
+ /* If a query restart will be required, do it here, rather than later of
+ ** after pointers to poslist buffers that may be invalidated by a restart
+ ** have been saved. */
+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr, fts3ExprRestartIfCb, (void*)&sCtx);
+ if( rc!=SQLITE_OK ) goto offsets_out;
+
/* Loop through the table columns, appending offset information to
** string-buffer res for each column.
*/
diff --git a/ext/fts3/fts3_term.c b/ext/fts3/fts3_term.c
index f3a9746a09..655dd9f35a 100644
--- a/ext/fts3/fts3_term.c
+++ b/ext/fts3/fts3_term.c
@@ -78,6 +78,8 @@ static int fts3termConnectMethod(
iIndex = atoi(argv[4]);
argc--;
}
+
+ *ppVtab = 0;
/* The user should specify a single argument - the name of an fts3 table. */
if( argc!=4 ){
@@ -95,12 +97,17 @@ static int fts3termConnectMethod(
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
if( rc!=SQLITE_OK ) return rc;
- nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
- p = (Fts3termTable *)sqlite3_malloc64(nByte);
+ nByte = sizeof(Fts3termTable);
+ p = (Fts3termTable *)sqlite3Fts3MallocZero(nByte);
if( !p ) return SQLITE_NOMEM;
- memset(p, 0, (size_t)nByte);
- p->pFts3Tab = (Fts3Table *)&p[1];
+ p->pFts3Tab = (Fts3Table*)sqlite3Fts3MallocZero(
+ sizeof(Fts3Table) + nDb + nFts3 + 2
+ );
+ if( p->pFts3Tab==0 ){
+ sqlite3_free(p);
+ return SQLITE_NOMEM;
+ }
p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
p->pFts3Tab->db = db;
@@ -130,6 +137,7 @@ static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){
sqlite3_finalize(pFts3->aStmt[i]);
}
sqlite3_free(pFts3->zSegmentsTbl);
+ sqlite3_free(pFts3);
sqlite3_free(p);
return SQLITE_OK;
}
diff --git a/ext/fts3/fts3_test.c b/ext/fts3/fts3_test.c
index 49a8476bf3..3c42a7bf02 100644
--- a/ext/fts3/fts3_test.c
+++ b/ext/fts3/fts3_test.c
@@ -18,14 +18,7 @@
** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly.
*/
-#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
-#else
-# include "tcl.h"
-# ifndef SQLITE_TCLAPI
-# define SQLITE_TCLAPI
-# endif
-#endif
+#include "tclsqlite.h"
#include
#include
@@ -167,7 +160,8 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
Tcl_Obj *pPhrasecount = 0;
Tcl_Obj **apExprToken;
- int nExprToken;
+ Tcl_Size nExprToken;
+ Tcl_Size nn;
UNUSED_PARAMETER(clientData);
@@ -201,23 +195,25 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
}
}
- rc = Tcl_ListObjGetElements(interp, objv[1], &doc.nToken, &apDocToken);
+ rc = Tcl_ListObjGetElements(interp, objv[1], &nn, &apDocToken);
+ doc.nToken = (int)nn;
if( rc!=TCL_OK ) goto near_match_out;
doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
for(ii=0; iiz = Tcl_GetStringFromObj(apToken[jj], &pT->n);
+ pT->z = Tcl_GetStringFromObj(apToken[jj], &nn);
+ pT->n = (int)nn;
}
- aPhrase[ii].nToken = nToken;
+ aPhrase[ii].nToken = (int)nToken;
}
for(ii=1; ii
/*
diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c
index 0f894943dd..5a449dec1e 100644
--- a/ext/fts3/fts3_write.c
+++ b/ext/fts3/fts3_write.c
@@ -5294,7 +5294,7 @@ static u64 fts3ChecksumIndex(
** If an error occurs (e.g. an OOM or IO error), return an SQLite error
** code. The final value of *pbOk is undefined in this case.
*/
-static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
+int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){
int rc = SQLITE_OK; /* Return code */
u64 cksum1 = 0; /* Checksum based on FTS index contents */
u64 cksum2 = 0; /* Checksum based on %_content contents */
@@ -5372,7 +5372,12 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
sqlite3_finalize(pStmt);
}
- *pbOk = (cksum1==cksum2);
+ if( rc==SQLITE_CORRUPT_VTAB ){
+ rc = SQLITE_OK;
+ *pbOk = 0;
+ }else{
+ *pbOk = (rc==SQLITE_OK && cksum1==cksum2);
+ }
return rc;
}
@@ -5412,7 +5417,7 @@ static int fts3DoIntegrityCheck(
){
int rc;
int bOk = 0;
- rc = fts3IntegrityCheck(p, &bOk);
+ rc = sqlite3Fts3IntegrityCheck(p, &bOk);
if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
return rc;
}
diff --git a/ext/fts3/unicode/mkunicode.tcl b/ext/fts3/unicode/mkunicode.tcl
index 58d90c68c7..1306629da8 100644
--- a/ext/fts3/unicode/mkunicode.tcl
+++ b/ext/fts3/unicode/mkunicode.tcl
@@ -628,6 +628,9 @@ proc print_categories {lMap} {
$caseP
$caseS
$caseZ
+
+ default:
+ return 1;
}
return 0;
}
diff --git a/ext/fts5/extract_api_docs.tcl b/ext/fts5/extract_api_docs.tcl
index 2320d70b7d..6ee71c262c 100644
--- a/ext/fts5/extract_api_docs.tcl
+++ b/ext/fts5/extract_api_docs.tcl
@@ -82,7 +82,7 @@ proc get_struct_docs {data names} {
set current_doc ""
}
set subject n/a
- regexp {^ *([[:alpha:]]*)} $line -> subject
+ regexp {^ *([[:alnum:]_]*)} $line -> subject
if {[lsearch $names $subject]>=0} {
set current_header $subject
} else {
@@ -108,8 +108,11 @@ proc get_tokenizer_docs {data} {
append res "
$line
\n"
continue
}
+ if {[regexp {FTS5_TOKENIZER} $line]} {
+ set line
+ }
if {[regexp {SYNONYM SUPPORT} $line]} {
- set line "
Synonym Support
"
+ set line "
Synonym Support
"
}
if {[string trim $line] == ""} {
append res "
\n"
@@ -223,10 +226,12 @@ proc main {data} {
Fts5ExtensionApi {
set struct [get_fts5_struct $data "^struct Fts5ExtensionApi" "^.;"]
set map [list]
+ set lKey [list]
foreach {k v} [get_struct_members $data] {
if {[string match x* $k]==0} continue
- lappend map $k "$k"
+ lappend lKey $k
}
+ foreach k [lsort -decr $lKey] { lappend map $k "$k" }
output [string map $map $struct]
}
diff --git a/ext/fts5/fts5.h b/ext/fts5/fts5.h
index 323d73a28f..907ea232a4 100644
--- a/ext/fts5/fts5.h
+++ b/ext/fts5/fts5.h
@@ -55,8 +55,8 @@ struct Fts5PhraseIter {
** EXTENSION API FUNCTIONS
**
** xUserData(pFts):
-** Return a copy of the context pointer the extension function was
-** registered with.
+** Return a copy of the pUserData pointer passed to the xCreateFunction()
+** API when the extension function was registered.
**
** xColumnTotalSize(pFts, iCol, pnToken):
** If parameter iCol is less than zero, set output variable *pnToken
@@ -88,8 +88,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -99,8 +102,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -116,12 +121,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -147,6 +153,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -228,6 +238,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
**
+** In all cases, matches are visited in (column ASC, offset ASC) order.
+** i.e. all those in column 0, sorted by offset, followed by those in
+** column 1, etc.
+**
** xPhraseNext()
** See xPhraseFirst above.
**
@@ -261,9 +275,80 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API may be slow in some cases if the token identified by parameters
+** iIdx and iToken matched a prefix token in the query. In most cases, the
+** first call to this API for each prefix token in the query is forced
+** to scan the portion of the full-text index that matches the prefix
+** token to collect the extra data required by this API. If the prefix
+** token matches a large number of token instances in the document set,
+** this may be a performance problem.
+**
+** If the user knows in advance that a query may use this API for a
+** prefix token, FTS5 may be configured to collect all required data as part
+** of the initial querying of the full-text index, avoiding the second scan
+** entirely. This also causes prefix queries that do not use this API to
+** run more slowly and use more memory. FTS5 may be configured in this way
+** either on a per-table basis using the [FTS5 insttoken | 'insttoken']
+** option, or on a per-query basis using the
+** [fts5_insttoken | fts5_insttoken()] user function.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
+**
+** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale)
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the locale associated
+** with column iCol of the current row. Usually, there is no associated
+** locale, and output parameters (*pzLocale) and (*pnLocale) are set
+** to NULL and 0, respectively. However, if the fts5_locale() function
+** was used to associate a locale with the value when it was inserted
+** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated
+** buffer containing the name of the locale in utf-8 encoding. (*pnLocale)
+** is set to the size in bytes of the buffer, not including the
+** nul-terminator.
+**
+** If successful, SQLITE_OK is returned. Or, if an error occurs, an
+** SQLite error code is returned. The final value of the output parameters
+** is undefined in this case.
+**
+** xTokenize_v2:
+** Tokenize text using the tokenizer belonging to the FTS5 table. This
+** API is the same as the xTokenize() API, except that it allows a tokenizer
+** locale to be specified.
*/
struct Fts5ExtensionApi {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 4 */
void *(*xUserData)(Fts5Context*);
@@ -298,6 +383,22 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
+
+ /* Below this point are iVersion>=4 only */
+ int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn);
+ int (*xTokenize_v2)(Fts5Context*,
+ const char *pText, int nText, /* Text to tokenize */
+ const char *pLocale, int nLocale, /* Locale to pass to tokenizer */
+ void *pCtx, /* Context passed to xToken() */
+ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
+ );
};
/*
@@ -318,7 +419,7 @@ struct Fts5ExtensionApi {
** A tokenizer instance is required to actually tokenize text.
**
** The first argument passed to this function is a copy of the (void*)
-** pointer provided by the application when the fts5_tokenizer object
+** pointer provided by the application when the fts5_tokenizer_v2 object
** was registered with FTS5 (the third argument to xCreateTokenizer()).
** The second and third arguments are an array of nul-terminated strings
** containing the tokenizer arguments, if any, specified following the
@@ -342,7 +443,7 @@ struct Fts5ExtensionApi {
** argument passed to this function is a pointer to an Fts5Tokenizer object
** returned by an earlier call to xCreate().
**
-** The second argument indicates the reason that FTS5 is requesting
+** The third argument indicates the reason that FTS5 is requesting
** tokenization of the supplied text. This is always one of the following
** four values:
**
@@ -366,6 +467,13 @@ struct Fts5ExtensionApi {
** on a columnsize=0 database.
**
**
+** The sixth and seventh arguments passed to xTokenize() - pLocale and
+** nLocale - are a pointer to a buffer containing the locale to use for
+** tokenization (e.g. "en_US") and its size in bytes, respectively. The
+** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in
+** which case nLocale is always 0) to indicate that the tokenizer should
+** use its default locale.
+**
** For each token in the input string, the supplied callback xToken() must
** be invoked. The first argument to it should be a copy of the pointer
** passed as the second argument to xTokenize(). The third and fourth
@@ -389,6 +497,30 @@ struct Fts5ExtensionApi {
** may abandon the tokenization and return any error code other than
** SQLITE_OK or SQLITE_DONE.
**
+** If the tokenizer is registered using an fts5_tokenizer_v2 object,
+** then the xTokenize() method has two additional arguments - pLocale
+** and nLocale. These specify the locale that the tokenizer should use
+** for the current request. If pLocale and nLocale are both 0, then the
+** tokenizer should use its default locale. Otherwise, pLocale points to
+** an nLocale byte buffer containing the name of the locale to use as utf-8
+** text. pLocale is not nul-terminated.
+**
+** FTS5_TOKENIZER
+**
+** There is also an fts5_tokenizer object. This is an older, deprecated,
+** version of fts5_tokenizer_v2. It is similar except that:
+**
+**
+**
There is no "iVersion" field, and
+**
The xTokenize() method does not take a locale argument.
+**
+**
+** Legacy fts5_tokenizer tokenizers must be registered using the
+** legacy xCreateTokenizer() function, instead of xCreateTokenizer_v2().
+**
+** Tokenizer implementations registered using either API may be retrieved
+** using both xFindTokenizer() and xFindTokenizer_v2().
+**
** SYNONYM SUPPORT
**
** Custom tokenizers may also support synonyms. Consider a case in which a
@@ -497,6 +629,33 @@ struct Fts5ExtensionApi {
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
+typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2;
+struct fts5_tokenizer_v2 {
+ int iVersion; /* Currently always 2 */
+
+ int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
+ void (*xDelete)(Fts5Tokenizer*);
+ int (*xTokenize)(Fts5Tokenizer*,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input text */
+ )
+ );
+};
+
+/*
+** New code should use the fts5_tokenizer_v2 type to define tokenizer
+** implementations. The following type is included for legacy applications
+** that still use it.
+*/
typedef struct fts5_tokenizer fts5_tokenizer;
struct fts5_tokenizer {
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
@@ -516,6 +675,7 @@ struct fts5_tokenizer {
);
};
+
/* Flags that may be passed as the third argument to xTokenize() */
#define FTS5_TOKENIZE_QUERY 0x0001
#define FTS5_TOKENIZE_PREFIX 0x0002
@@ -535,7 +695,7 @@ struct fts5_tokenizer {
*/
typedef struct fts5_api fts5_api;
struct fts5_api {
- int iVersion; /* Currently always set to 2 */
+ int iVersion; /* Currently always set to 3 */
/* Create a new tokenizer */
int (*xCreateTokenizer)(
@@ -562,6 +722,25 @@ struct fts5_api {
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
+
+ /* APIs below this point are only available if iVersion>=3 */
+
+ /* Create a new tokenizer */
+ int (*xCreateTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void *pUserData,
+ fts5_tokenizer_v2 *pTokenizer,
+ void (*xDestroy)(void*)
+ );
+
+ /* Find an existing tokenizer */
+ int (*xFindTokenizer_v2)(
+ fts5_api *pApi,
+ const char *zName,
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer
+ );
};
/*
diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h
index 8bbafbaaf4..832f9ad477 100644
--- a/ext/fts5/fts5Int.h
+++ b/ext/fts5/fts5Int.h
@@ -59,6 +59,22 @@ typedef sqlite3_uint64 u64;
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+/* The uptr type is an unsigned integer large enough to hold a pointer
+*/
+#if defined(HAVE_STDINT_H)
+ typedef uintptr_t uptr;
+#elif SQLITE_PTRSIZE==4
+ typedef u32 uptr;
+#else
+ typedef u64 uptr;
+#endif
+
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
+#else
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
+#endif
+
#endif
/* Truncate very long tokens to this many bytes. Hard limit is
@@ -142,6 +158,18 @@ struct Fts5Colset {
*/
typedef struct Fts5Config Fts5Config;
+typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
+
+struct Fts5TokenizerConfig {
+ Fts5Tokenizer *pTok;
+ fts5_tokenizer_v2 *pApi2;
+ fts5_tokenizer *pApi1;
+ const char **azArg;
+ int nArg;
+ int ePattern; /* FTS_PATTERN_XXX constant */
+ const char *pLocale; /* Current locale to use */
+ int nLocale; /* Size of pLocale in bytes */
+};
/*
** An instance of the following structure encodes all information that can
@@ -181,9 +209,12 @@ typedef struct Fts5Config Fts5Config;
**
** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex);
**
+** bLocale:
+** Set to true if locale=1 was specified when the table was created.
*/
struct Fts5Config {
sqlite3 *db; /* Database handle */
+ Fts5Global *pGlobal; /* Global fts5 object for handle db */
char *zDb; /* Database holding FTS index (e.g. "main") */
char *zName; /* Name of FTS index */
int nCol; /* Number of columns */
@@ -193,15 +224,17 @@ struct Fts5Config {
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
+ int bContentlessUnindexed; /* "contentless_unindexed=" option (dflt=0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
+ int bTokendata; /* "tokendata=" option value (dflt==0) */
+ int bLocale; /* "locale=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
- Fts5Tokenizer *pTok;
- fts5_tokenizer *pTokApi;
+ Fts5TokenizerConfig t;
int bLock; /* True when table is preparing statement */
- int ePattern; /* FTS_PATTERN_XXX constant */
+
/* Values loaded from the %_config table */
int iVersion; /* fts5 file format 'version' */
@@ -214,7 +247,8 @@ struct Fts5Config {
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
int bSecureDelete; /* 'secure-delete' */
- int nDeleteMerge; /* 'deletemerge' */
+ int nDeleteMerge; /* 'deletemerge' */
+ int bPrefixInsttoken; /* 'prefix-insttoken' */
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -230,9 +264,10 @@ struct Fts5Config {
#define FTS5_CURRENT_VERSION 4
#define FTS5_CURRENT_VERSION_SECUREDELETE 5
-#define FTS5_CONTENT_NORMAL 0
-#define FTS5_CONTENT_NONE 1
-#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_NORMAL 0
+#define FTS5_CONTENT_NONE 1
+#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_UNINDEXED 3
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
@@ -267,6 +302,8 @@ int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*);
int sqlite3Fts5ConfigParseRank(const char*, char**, char**);
+void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...);
+
/*
** End of interface to code in fts5_config.c.
**************************************************************************/
@@ -311,7 +348,7 @@ char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
void sqlite3Fts5Put32(u8*, int);
int sqlite3Fts5Get32(const u8*);
-#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32)
+#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF)
#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF)
typedef struct Fts5PoslistReader Fts5PoslistReader;
@@ -384,17 +421,19 @@ struct Fts5IndexIter {
/*
** Values used as part of the flags argument passed to IndexQuery().
*/
-#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
-#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
-#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
-#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
+#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
+#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
+#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
+#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
-#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
-#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
-#define FTS5INDEX_QUERY_SKIPHASH 0x0040
+#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
+#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
+#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
+#define FTS5INDEX_QUERY_SCANONETERM 0x0100
/*
** Create/destroy an Fts5Index object.
@@ -463,6 +502,17 @@ void *sqlite3Fts5StructureRef(Fts5Index*);
void sqlite3Fts5StructureRelease(void*);
int sqlite3Fts5StructureTest(Fts5Index*, void*);
+/*
+** Used by xInstToken():
+*/
+int sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+);
/*
** Insert or remove data to or from the index. Each time a document is
@@ -540,6 +590,13 @@ int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
+void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);
+
+/* Used to populate hash tables for xInstToken in detail=none/column mode. */
+int sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
+);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
@@ -583,18 +640,20 @@ struct Fts5Table {
Fts5Index *pIndex; /* Full-text index */
};
-int sqlite3Fts5GetTokenizer(
- Fts5Global*,
- const char **azArg,
- int nArg,
- Fts5Config*,
- char **pzErr
-);
+int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig);
Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
int sqlite3Fts5FlushToDisk(Fts5Table*);
+void sqlite3Fts5ClearLocale(Fts5Config *pConfig);
+void sqlite3Fts5SetLocale(Fts5Config *pConfig, const char *pLoc, int nLoc);
+
+int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal);
+int sqlite3Fts5DecodeLocaleValue(sqlite3_value *pVal,
+ const char **ppText, int *pnText, const char **ppLoc, int *pnLoc
+);
+
/*
** End of interface to code in fts5.c.
**************************************************************************/
@@ -645,6 +704,7 @@ void sqlite3Fts5HashScanNext(Fts5Hash*);
int sqlite3Fts5HashScanEof(Fts5Hash*);
void sqlite3Fts5HashScanEntry(Fts5Hash *,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
);
@@ -673,8 +733,8 @@ int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
int sqlite3Fts5DropAll(Fts5Config*);
int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
-int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
-int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
+int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
+int sqlite3Fts5StorageContentInsert(Fts5Storage *p, int, sqlite3_value**, i64*);
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
@@ -699,6 +759,9 @@ int sqlite3Fts5StorageOptimize(Fts5Storage *p);
int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
int sqlite3Fts5StorageReset(Fts5Storage *p);
+void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
+int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
+
/*
** End of interface to code in fts5_storage.c.
**************************************************************************/
@@ -771,6 +834,10 @@ int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
+int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
+int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
+void sqlite3Fts5ExprClearTokens(Fts5Expr*);
+
/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
@@ -847,6 +914,7 @@ int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok
);
+int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig*);
/*
** End of interface to code in fts5_tokenizer.c.
**************************************************************************/
diff --git a/ext/fts5/fts5_aux.c b/ext/fts5/fts5_aux.c
index fa58b9aac3..ad578156da 100644
--- a/ext/fts5/fts5_aux.c
+++ b/ext/fts5/fts5_aux.c
@@ -211,6 +211,14 @@ static int fts5HighlightCb(
}
if( iPos==p->iRangeEnd ){
+ if( p->bOpen ){
+ if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
+ }
+ fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
+ }
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
}
@@ -218,6 +226,7 @@ static int fts5HighlightCb(
return rc;
}
+
/*
** Implementation of highlight() function.
*/
@@ -244,14 +253,23 @@ static void fts5HighlightFunction(
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
-
- if( ctx.zIn ){
+ if( rc==SQLITE_RANGE ){
+ sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = SQLITE_OK;
+ }else if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iCol */
+ int nLoc = 0; /* Size of pLoc in bytes */
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb
+ );
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -448,6 +466,8 @@ static void fts5SnippetFunction(
memset(&sFinder, 0, sizeof(Fts5SFinder));
for(i=0; ixColumnText(pFts, i, &sFinder.zDoc, &nDoc);
if( rc!=SQLITE_OK ) break;
- rc = pApi->xTokenize(pFts,
- sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
+ rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc);
+ if( rc!=SQLITE_OK ) break;
+ rc = pApi->xTokenize_v2(pFts,
+ sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb
);
if( rc!=SQLITE_OK ) break;
rc = pApi->xColumnSize(pFts, i, &nDocsize);
@@ -514,6 +536,9 @@ static void fts5SnippetFunction(
rc = pApi->xColumnSize(pFts, iBestCol, &nColSize);
}
if( ctx.zIn ){
+ const char *pLoc = 0; /* Locale of column iBestCol */
+ int nLoc = 0; /* Bytes in pLoc */
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter);
}
@@ -532,7 +557,12 @@ static void fts5SnippetFunction(
}
if( rc==SQLITE_OK ){
- rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
+ rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pApi->xTokenize_v2(
+ pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb
+ );
}
if( ctx.bOpen ){
fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
@@ -716,6 +746,53 @@ static void fts5Bm25Function(
}
}
+/*
+** Implementation of fts5_get_locale() function.
+*/
+static void fts5GetLocaleFunction(
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
+ sqlite3_context *pCtx, /* Context for returning result/error */
+ int nVal, /* Number of values in apVal[] array */
+ sqlite3_value **apVal /* Array of trailing arguments */
+){
+ int iCol = 0;
+ int eType = 0;
+ int rc = SQLITE_OK;
+ const char *zLocale = 0;
+ int nLocale = 0;
+
+ /* xColumnLocale() must be available */
+ assert( pApi->iVersion>=4 );
+
+ if( nVal!=1 ){
+ const char *z = "wrong number of arguments to function fts5_get_locale()";
+ sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ eType = sqlite3_value_numeric_type(apVal[0]);
+ if( eType!=SQLITE_INTEGER ){
+ const char *z = "non-integer argument passed to function fts5_get_locale()";
+ sqlite3_result_error(pCtx, z, -1);
+ return;
+ }
+
+ iCol = sqlite3_value_int(apVal[0]);
+ if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){
+ sqlite3_result_error_code(pCtx, SQLITE_RANGE);
+ return;
+ }
+
+ rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale);
+ if( rc!=SQLITE_OK ){
+ sqlite3_result_error_code(pCtx, rc);
+ return;
+ }
+
+ sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT);
+}
+
int sqlite3Fts5AuxInit(fts5_api *pApi){
struct Builtin {
const char *zFunc; /* Function name (nul-terminated) */
@@ -723,9 +800,10 @@ int sqlite3Fts5AuxInit(fts5_api *pApi){
fts5_extension_function xFunc;/* Callback function */
void (*xDestroy)(void*); /* Destructor function */
} aBuiltin [] = {
- { "snippet", 0, fts5SnippetFunction, 0 },
- { "highlight", 0, fts5HighlightFunction, 0 },
- { "bm25", 0, fts5Bm25Function, 0 },
+ { "snippet", 0, fts5SnippetFunction, 0 },
+ { "highlight", 0, fts5HighlightFunction, 0 },
+ { "bm25", 0, fts5Bm25Function, 0 },
+ { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 },
};
int rc = SQLITE_OK; /* Return code */
int i; /* To iterate through builtin functions */
diff --git a/ext/fts5/fts5_buffer.c b/ext/fts5/fts5_buffer.c
index b9614e1290..891ef0203a 100644
--- a/ext/fts5/fts5_buffer.c
+++ b/ext/fts5/fts5_buffer.c
@@ -68,6 +68,7 @@ void sqlite3Fts5BufferAppendBlob(
){
if( nData ){
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ assert( pBuf->p!=0 );
memcpy(&pBuf->p[pBuf->n], pData, nData);
pBuf->n += nData;
}
@@ -169,6 +170,7 @@ int sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
){
int i = *pi;
+ assert( a!=0 || i==0 );
if( i>=n ){
/* EOF */
*piOff = -1;
@@ -176,6 +178,7 @@ int sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
u32 iVal;
+ assert( a!=0 );
fts5FastGetVarint32(a, i, iVal);
if( iVal<=1 ){
if( iVal==0 ){
diff --git a/ext/fts5/fts5_config.c b/ext/fts5/fts5_config.c
index 5d0770502e..eea82b046d 100644
--- a/ext/fts5/fts5_config.c
+++ b/ext/fts5/fts5_config.c
@@ -234,7 +234,6 @@ static int fts5ConfigSetEnum(
** eventually free any such error message using sqlite3_free().
*/
static int fts5ConfigParseSpecial(
- Fts5Global *pGlobal,
Fts5Config *pConfig, /* Configuration object to update */
const char *zCmd, /* Special command to parse */
const char *zArg, /* Argument to parse */
@@ -242,6 +241,7 @@ static int fts5ConfigParseSpecial(
){
int rc = SQLITE_OK;
int nCmd = (int)strlen(zCmd);
+
if( sqlite3_strnicmp("prefix", zCmd, nCmd)==0 ){
const int nByte = sizeof(int) * FTS5_MAX_PREFIX_INDEXES;
const char *p;
@@ -298,12 +298,11 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg;
sqlite3_int64 nArg = strlen(zArg) + 1;
- char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg);
- char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
- char *pSpace = pDel;
+ char **azArg = sqlite3Fts5MallocZero(&rc, (sizeof(char*) + 2) * nArg);
- if( azArg && pSpace ){
- if( pConfig->pTok ){
+ if( azArg ){
+ char *pSpace = (char*)&azArg[nArg];
+ if( pConfig->t.azArg ){
*pzErr = sqlite3_mprintf("multiple tokenize=... directives");
rc = SQLITE_ERROR;
}else{
@@ -326,16 +325,14 @@ static int fts5ConfigParseSpecial(
*pzErr = sqlite3_mprintf("parse error in tokenize directive");
rc = SQLITE_ERROR;
}else{
- rc = sqlite3Fts5GetTokenizer(pGlobal,
- (const char**)azArg, (int)nArg, pConfig,
- pzErr
- );
+ pConfig->t.azArg = (const char**)azArg;
+ pConfig->t.nArg = nArg;
+ azArg = 0;
}
}
}
-
sqlite3_free(azArg);
- sqlite3_free(pDel);
+
return rc;
}
@@ -364,6 +361,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("contentless_unindexed", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessUnindexed = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
@@ -384,6 +391,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed locale=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bLocale = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){
const Fts5Enum aDetail[] = {
{ "none", FTS5_DETAIL_NONE },
@@ -398,20 +415,20 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed tokendata=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bTokendata = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
*pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
return SQLITE_ERROR;
}
-/*
-** Allocate an instance of the default tokenizer ("simple") at
-** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
-** code if an error occurs.
-*/
-static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
- assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
- return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
-}
-
/*
** Gobble up the first bareword or quoted word from the input buffer zIn.
** Return a pointer to the character immediately following the last in
@@ -471,7 +488,8 @@ static int fts5ConfigParseColumn(
Fts5Config *p,
char *zCol,
char *zArg,
- char **pzErr
+ char **pzErr,
+ int *pbUnindexed
){
int rc = SQLITE_OK;
if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
@@ -482,6 +500,7 @@ static int fts5ConfigParseColumn(
}else if( zArg ){
if( 0==sqlite3_stricmp(zArg, "unindexed") ){
p->abUnindexed[p->nCol] = 1;
+ *pbUnindexed = 1;
}else{
*pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
rc = SQLITE_ERROR;
@@ -502,11 +521,26 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
if( p->eContent!=FTS5_CONTENT_NONE ){
+ assert( p->eContent==FTS5_CONTENT_EXTERNAL
+ || p->eContent==FTS5_CONTENT_NORMAL
+ || p->eContent==FTS5_CONTENT_UNINDEXED
+ );
for(i=0; inCol; i++){
if( p->eContent==FTS5_CONTENT_EXTERNAL ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
- }else{
+ }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
+ }else{
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
+ }
+ }
+ }
+ if( p->eContent==FTS5_CONTENT_NORMAL && p->bLocale ){
+ for(i=0; inCol; i++){
+ if( p->abUnindexed[i]==0 ){
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.l%d", i);
+ }else{
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
}
}
}
@@ -540,10 +574,12 @@ int sqlite3Fts5ConfigParse(
Fts5Config *pRet; /* New object to return */
int i;
sqlite3_int64 nByte;
+ int bUnindexed = 0; /* True if there are one or more UNINDEXED */
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
memset(pRet, 0, sizeof(Fts5Config));
+ pRet->pGlobal = pGlobal;
pRet->db = db;
pRet->iCookie = -1;
@@ -592,13 +628,13 @@ int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}else{
if( bOption ){
- rc = fts5ConfigParseSpecial(pGlobal, pRet,
+ rc = fts5ConfigParseSpecial(pRet,
ALWAYS(zOne)?zOne:"",
zTwo?zTwo:"",
pzErr
);
}else{
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
+ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
zOne = 0;
}
}
@@ -630,21 +666,30 @@ int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
- /* If a tokenizer= option was successfully parsed, the tokenizer has
- ** already been allocated. Otherwise, allocate an instance of the default
- ** tokenizer (unicode61) now. */
- if( rc==SQLITE_OK && pRet->pTok==0 ){
- rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
+ /* We only allow contentless_unindexed=1 if the table is actually a
+ ** contentless one.
+ */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessUnindexed
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_unindexed=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
}
/* If no zContent option was specified, fill in the default values. */
if( rc==SQLITE_OK && pRet->zContent==0 ){
const char *zTail = 0;
- assert( pRet->eContent==FTS5_CONTENT_NORMAL
- || pRet->eContent==FTS5_CONTENT_NONE
+ assert( pRet->eContent==FTS5_CONTENT_NORMAL
+ || pRet->eContent==FTS5_CONTENT_NONE
);
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
zTail = "content";
+ }else if( bUnindexed && pRet->bContentlessUnindexed ){
+ pRet->eContent = FTS5_CONTENT_UNINDEXED;
+ zTail = "content";
}else if( pRet->bColumnsize ){
zTail = "docsize";
}
@@ -678,9 +723,14 @@ int sqlite3Fts5ConfigParse(
void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
if( pConfig ){
int i;
- if( pConfig->pTok ){
- pConfig->pTokApi->xDelete(pConfig->pTok);
+ if( pConfig->t.pTok ){
+ if( pConfig->t.pApi1 ){
+ pConfig->t.pApi1->xDelete(pConfig->t.pTok);
+ }else{
+ pConfig->t.pApi2->xDelete(pConfig->t.pTok);
+ }
}
+ sqlite3_free((char*)pConfig->t.azArg);
sqlite3_free(pConfig->zDb);
sqlite3_free(pConfig->zName);
for(i=0; inCol; i++){
@@ -755,10 +805,24 @@ int sqlite3Fts5Tokenize(
void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
){
- if( pText==0 ) return SQLITE_OK;
- return pConfig->pTokApi->xTokenize(
- pConfig->pTok, pCtx, flags, pText, nText, xToken
- );
+ int rc = SQLITE_OK;
+ if( pText ){
+ if( pConfig->t.pTok==0 ){
+ rc = sqlite3Fts5LoadTokenizer(pConfig);
+ }
+ if( rc==SQLITE_OK ){
+ if( pConfig->t.pApi1 ){
+ rc = pConfig->t.pApi1->xTokenize(
+ pConfig->t.pTok, pCtx, flags, pText, nText, xToken
+ );
+ }else{
+ rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags,
+ pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken
+ );
+ }
+ }
+ }
+ return rc;
}
/*
@@ -962,6 +1026,19 @@ int sqlite3Fts5ConfigSetValue(
}else{
pConfig->bSecureDelete = (bVal ? 1 : 0);
}
+ }
+
+ else if( 0==sqlite3_stricmp(zKey, "insttoken") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bPrefixInsttoken = (bVal ? 1 : 0);
+ }
+
}else{
*pbBadkey = 1;
}
@@ -1012,13 +1089,10 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
&& iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
){
rc = SQLITE_ERROR;
- if( pConfig->pzErrmsg ){
- assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
- "(found %d, expected %d or %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
- );
- }
+ sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
}else{
pConfig->iVersion = iVersion;
}
@@ -1028,3 +1102,26 @@ int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
}
return rc;
}
+
+/*
+** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer
+** containing the error message created using printf() style formatting
+** string zFmt and its trailing arguments.
+*/
+void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){
+ va_list ap; /* ... printf arguments */
+ char *zMsg = 0;
+
+ va_start(ap, zFmt);
+ zMsg = sqlite3_vmprintf(zFmt, ap);
+ if( pConfig->pzErrmsg ){
+ assert( *pConfig->pzErrmsg==0 );
+ *pConfig->pzErrmsg = zMsg;
+ }else{
+ sqlite3_free(zMsg);
+ }
+
+ va_end(ap);
+}
+
+
diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c
index f5101ba065..877c3f79c5 100644
--- a/ext/fts5/fts5_expr.c
+++ b/ext/fts5/fts5_expr.c
@@ -54,7 +54,7 @@ struct Fts5Expr {
/*
** eType:
-** Expression node type. Always one of:
+** Expression node type. Usually one of:
**
** FTS5_AND (nChild, apChild valid)
** FTS5_OR (nChild, apChild valid)
@@ -62,6 +62,10 @@ struct Fts5Expr {
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
**
+** An expression node with eType==0 may also exist. It always matches zero
+** rows. This is created when a phrase containing no tokens is parsed.
+** e.g. "".
+**
** iHeight:
** Distance from this node to furthest leaf. This is always 0 for nodes
** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
@@ -100,7 +104,9 @@ struct Fts5ExprNode {
struct Fts5ExprTerm {
u8 bPrefix; /* True for a prefix term */
u8 bFirst; /* True if token must be first in column */
- char *zTerm; /* nul-terminated term */
+ char *pTerm; /* Term data */
+ int nQueryTerm; /* Effective size of term in bytes */
+ int nFullTerm; /* Size of term in bytes incl. tokendata */
Fts5IndexIter *pIter; /* Iterator for this term */
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
};
@@ -280,11 +286,12 @@ int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
- if( iColnCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
+ if( sParse.rc==SQLITE_OK && iColnCol ){
int n = sizeof(Fts5Colset);
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
@@ -301,15 +308,7 @@ int sqlite3Fts5ExprNew(
sParse.rc = SQLITE_NOMEM;
sqlite3Fts5ParseNodeFree(sParse.pExpr);
}else{
- if( !sParse.pExpr ){
- const int nByte = sizeof(Fts5ExprNode);
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte);
- if( pNew->pRoot ){
- pNew->pRoot->bEof = 1;
- }
- }else{
- pNew->pRoot = sParse.pExpr;
- }
+ pNew->pRoot = sParse.pExpr;
pNew->pIndex = 0;
pNew->pConfig = pConfig;
pNew->apExprPhrase = sParse.apPhrase;
@@ -322,7 +321,11 @@ int sqlite3Fts5ExprNew(
}
sqlite3_free(sParse.apPhrase);
- *pzErr = sParse.zErr;
+ if( 0==*pzErr ){
+ *pzErr = sParse.zErr;
+ }else{
+ sqlite3_free(sParse.zErr);
+ }
return sParse.rc;
}
@@ -967,7 +970,7 @@ static int fts5ExprNearInitAll(
p->pIter = 0;
}
rc = sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ pExpr->pIndex, p->pTerm, p->nQueryTerm,
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
pNear->pColset,
@@ -1123,7 +1126,7 @@ static int fts5ExprNodeTest_STRING(
}
}else{
Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter;
- if( pIter->iRowid==iLast || pIter->bEof ) continue;
+ if( pIter->iRowid==iLast ) continue;
bMatch = 0;
if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){
return rc;
@@ -1604,7 +1607,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
Fts5ExprTerm *pSyn;
Fts5ExprTerm *pNext;
Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- sqlite3_free(pTerm->zTerm);
+ sqlite3_free(pTerm->pTerm);
sqlite3Fts5IterClose(pTerm->pIter);
for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
pNext = pSyn->pSynonym;
@@ -1645,9 +1648,6 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
- if( pPhrase==0 ){
- return pNear;
- }
if( pNear==0 ){
sqlite3_int64 nByte;
nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*);
@@ -1702,6 +1702,7 @@ Fts5ExprNearset *sqlite3Fts5ParseNearset(
typedef struct TokenCtx TokenCtx;
struct TokenCtx {
Fts5ExprPhrase *pPhrase;
+ Fts5Config *pConfig;
int rc;
};
@@ -1735,8 +1736,12 @@ static int fts5ParseTokenize(
rc = SQLITE_NOMEM;
}else{
memset(pSyn, 0, (size_t)nByte);
- pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
- memcpy(pSyn->zTerm, pToken, nToken);
+ pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
+ pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata ){
+ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
+ }
+ memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
@@ -1761,7 +1766,11 @@ static int fts5ParseTokenize(
if( rc==SQLITE_OK ){
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
+ pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
+ }
}
}
@@ -1828,6 +1837,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pAppend;
+ sCtx.pConfig = pConfig;
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
@@ -1859,6 +1869,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
}else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
+ assert( pParse->apPhrase!=0 );
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
}
@@ -1875,12 +1886,15 @@ int sqlite3Fts5ExprClonePhrase(
Fts5Expr **ppNew
){
int rc = SQLITE_OK; /* Return code */
- Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
+ Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
- TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
-
- pOrig = pExpr->apExprPhrase[iPhrase];
- pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
+ if( !pExpr || iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ rc = SQLITE_RANGE;
+ }else{
+ pOrig = pExpr->apExprPhrase[iPhrase];
+ pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ }
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
@@ -1893,7 +1907,7 @@ int sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlite3_int64 nByte;
@@ -1907,26 +1921,27 @@ int sqlite3Fts5ExprClonePhrase(
}
}
- if( pOrig->nTerm ){
- int i; /* Used to iterate through phrase terms */
- for(i=0; rc==SQLITE_OK && inTerm; i++){
- int tflags = 0;
- Fts5ExprTerm *p;
- for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
- const char *zTerm = p->zTerm;
- rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
- 0, 0);
- tflags = FTS5_TOKEN_COLOCATED;
- }
- if( rc==SQLITE_OK ){
- sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
- sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ if( rc==SQLITE_OK ){
+ if( pOrig->nTerm ){
+ int i; /* Used to iterate through phrase terms */
+ sCtx.pConfig = pExpr->pConfig;
+ for(i=0; rc==SQLITE_OK && inTerm; i++){
+ int tflags = 0;
+ Fts5ExprTerm *p;
+ for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
+ rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
+ tflags = FTS5_TOKEN_COLOCATED;
+ }
+ if( rc==SQLITE_OK ){
+ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ }
}
+ }else{
+ /* This happens when parsing a token or quoted phrase that contains
+ ** no token characters at all. (e.g ... MATCH '""'). */
+ sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
- }else{
- /* This happens when parsing a token or quoted phrase that contains
- ** no token characters at all. (e.g ... MATCH '""'). */
- sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
}
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
@@ -2242,6 +2257,9 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
}
+/*
+** Add pSub as a child of p.
+*/
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
@@ -2296,11 +2314,13 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
+ Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
+ Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
- pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
- &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
- );
+ pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
+ pTo->nQueryTerm = p->nQueryTerm;
+ pTo->nFullTerm = p->nFullTerm;
pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
@@ -2384,19 +2404,23 @@ Fts5ExprNode *sqlite3Fts5ParseNode(
"fts5: %s queries are not supported (detail!=full)",
pNear->nPhrase==1 ? "phrase": "NEAR"
);
- sqlite3_free(pRet);
+ sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
+ pNear = 0;
+ assert( pLeft==0 && pRight==0 );
}
}
}else{
+ assert( pNear==0 );
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ pLeft = pRight = 0;
if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
sqlite3Fts5ParseError(pParse,
"fts5 expression tree is too large (maximum depth %d)",
SQLITE_FTS5_MAX_EXPR_DEPTH
);
- sqlite3_free(pRet);
+ sqlite3Fts5ParseNodeFree(pRet);
pRet = 0;
}
}
@@ -2434,6 +2458,7 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
assert( pRight->eType==FTS5_STRING
|| pRight->eType==FTS5_TERM
|| pRight->eType==FTS5_EOF
+ || (pRight->eType==FTS5_AND && pParse->bPhraseToAnd)
);
if( pLeft->eType==FTS5_AND ){
@@ -2447,6 +2472,8 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
);
if( pRight->eType==FTS5_EOF ){
+ assert( pParse->apPhrase!=0 );
+ assert( pParse->nPhrase>0 );
assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
sqlite3Fts5ParseNodeFree(pRight);
pRet = pLeft;
@@ -2485,16 +2512,17 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
/* Determine the maximum amount of space required. */
for(p=pTerm; p; p=p->pSynonym){
- nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
+ nByte += pTerm->nQueryTerm * 2 + 3 + 2;
}
zQuoted = sqlite3_malloc64(nByte);
if( zQuoted ){
int i = 0;
for(p=pTerm; p; p=p->pSynonym){
- char *zIn = p->zTerm;
+ char *zIn = p->pTerm;
+ char *zEnd = &zIn[p->nQueryTerm];
zQuoted[i++] = '"';
- while( *zIn ){
+ while( zInnTerm; iTerm++){
- char *zTerm = pPhrase->aTerm[iTerm].zTerm;
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
+ Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
+ zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ",
+ p->nQueryTerm, p->pTerm
+ );
if( pPhrase->aTerm[iTerm].bPrefix ){
zRet = fts5PrintfAppend(zRet, "*");
}
@@ -2974,6 +3004,17 @@ static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
return 0;
}
+/*
+** pToken is a buffer nToken bytes in size that may or may not contain
+** an embedded 0x00 byte. If it does, return the number of bytes in
+** the buffer before the 0x00. If it does not, return nToken.
+*/
+static int fts5QueryTerm(const char *pToken, int nToken){
+ int ii;
+ for(ii=0; iipExpr;
int i;
+ int nQuery = nToken;
+ i64 iRowid = pExpr->pRoot->iRowid;
UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
+ if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
+ if( pExpr->pConfig->bTokendata ){
+ nQuery = fts5QueryTerm(pToken, nQuery);
+ }
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
for(i=0; inPhrase; i++){
- Fts5ExprTerm *pTerm;
+ Fts5ExprTerm *pT;
if( p->aPopulator[i].bOk==0 ) continue;
- for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = (int)strlen(pTerm->zTerm);
- if( (nTerm==nToken || (nTermbPrefix))
- && memcmp(pTerm->zTerm, pToken, nTerm)==0
+ for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
+ if( (pT->nQueryTerm==nQuery || (pT->nQueryTermbPrefix))
+ && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
){
int rc = sqlite3Fts5PoslistWriterAppend(
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
);
+ if( rc==SQLITE_OK && (pExpr->pConfig->bTokendata || pT->bPrefix) ){
+ int iCol = p->iOff>>32;
+ int iTokOff = p->iOff & 0x7FFFFFFF;
+ rc = sqlite3Fts5IndexIterWriteTokendata(
+ pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
+ );
+ }
if( rc ) return rc;
break;
}
@@ -3054,6 +3106,7 @@ static int fts5ExprCheckPoslists(Fts5ExprNode *pNode, i64 iRowid){
pNode->iRowid = iRowid;
pNode->bEof = 0;
switch( pNode->eType ){
+ case 0:
case FTS5_TERM:
case FTS5_STRING:
return (pNode->pNear->apPhrase[0]->poslist.n>0);
@@ -3135,3 +3188,79 @@ int sqlite3Fts5ExprPhraseCollist(
return rc;
}
+
+/*
+** Does the work of the fts5_api.xQueryToken() API method.
+*/
+int sqlite3Fts5ExprQueryToken(
+ Fts5Expr *pExpr,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+
+ *ppOut = pPhrase->aTerm[iToken].pTerm;
+ *pnOut = pPhrase->aTerm[iToken].nFullTerm;
+ return SQLITE_OK;
+}
+
+/*
+** Does the work of the fts5_api.xInstToken() API method.
+*/
+int sqlite3Fts5ExprInstToken(
+ Fts5Expr *pExpr,
+ i64 iRowid,
+ int iPhrase,
+ int iCol,
+ int iOff,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+ Fts5ExprTerm *pTerm = 0;
+ int rc = SQLITE_OK;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+ pTerm = &pPhrase->aTerm[iToken];
+ if( pExpr->pConfig->bTokendata || pTerm->bPrefix ){
+ rc = sqlite3Fts5IterToken(
+ pTerm->pIter, pTerm->pTerm, pTerm->nQueryTerm,
+ iRowid, iCol, iOff+iToken, ppOut, pnOut
+ );
+ }else{
+ *ppOut = pTerm->pTerm;
+ *pnOut = pTerm->nFullTerm;
+ }
+ return rc;
+}
+
+/*
+** Clear the token mappings for all Fts5IndexIter objects mannaged by
+** the expression passed as the only argument.
+*/
+void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
+ int ii;
+ for(ii=0; iinPhrase; ii++){
+ Fts5ExprTerm *pT;
+ for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
+ sqlite3Fts5IndexIterClearTokendata(pT->pIter);
+ }
+ }
+}
diff --git a/ext/fts5/fts5_hash.c b/ext/fts5/fts5_hash.c
index 391791c7ac..5e0959aa8e 100644
--- a/ext/fts5/fts5_hash.c
+++ b/ext/fts5/fts5_hash.c
@@ -36,10 +36,15 @@ struct Fts5Hash {
/*
** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (a nul-terminated string) and
-** its current data are stored in a single memory allocation. The
-** key immediately follows the object in memory. The position list
-** data immediately follows the key data in memory.
+** following type. Each object, its key, and its current data are stored
+** in a single memory allocation. The key immediately follows the object
+** in memory. The position list data immediately follows the key data
+** in memory.
+**
+** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
+** byte identifying the index (either the main term index or a prefix-index),
+** followed by the term data. For example: "0token". There is no
+** nul-terminator - in this case nKey=6.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
@@ -174,8 +179,7 @@ static int fts5HashResize(Fts5Hash *pHash){
unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
- (int)strlen(fts5EntryKey(p)));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
@@ -259,7 +263,7 @@ int sqlite3Fts5HashWrite(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
char *zKey = fts5EntryKey(p);
if( zKey[0]==bByte
- && p->nKey==nToken
+ && p->nKey==nToken+1
&& memcmp(&zKey[1], pToken, nToken)==0
){
break;
@@ -289,9 +293,9 @@ int sqlite3Fts5HashWrite(
zKey[0] = bByte;
memcpy(&zKey[1], pToken, nToken);
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
- p->nKey = nToken;
+ p->nKey = nToken+1;
zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
+ p->nData = nToken+1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
@@ -408,12 +412,17 @@ static Fts5HashEntry *fts5HashEntryMerge(
*ppOut = p1;
p1 = 0;
}else{
- int i = 0;
char *zKey1 = fts5EntryKey(p1);
char *zKey2 = fts5EntryKey(p2);
- while( zKey1[i]==zKey2[i] ) i++;
+ int nMin = MIN(p1->nKey, p2->nKey);
+
+ int cmp = memcmp(zKey1, zKey2, nMin);
+ if( cmp==0 ){
+ cmp = p1->nKey - p2->nKey;
+ }
+ assert( cmp!=0 );
- if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
+ if( cmp>0 ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
@@ -455,7 +464,7 @@ static int fts5HashEntrySort(
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
if( pTerm==0
- || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
+ || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
@@ -494,12 +503,11 @@ int sqlite3Fts5HashQuery(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
zKey = fts5EntryKey(p);
- assert( p->nKey+1==(int)strlen(zKey) );
- if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
+ if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
}
if( p ){
- int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
+ int nHashPre = sizeof(Fts5HashEntry) + nTerm;
int nList = p->nData - nHashPre;
u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
if( pRet ){
@@ -560,19 +568,22 @@ int sqlite3Fts5HashScanEof(Fts5Hash *p){
void sqlite3Fts5HashScanEntry(
Fts5Hash *pHash,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
char *zKey = fts5EntryKey(p);
- int nTerm = (int)strlen(zKey);
+ int nTerm = p->nKey;
fts5HashAddPoslistSize(pHash, p, 0);
*pzTerm = zKey;
- *ppDoclist = (const u8*)&zKey[nTerm+1];
- *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
+ *pnTerm = nTerm;
+ *ppDoclist = (const u8*)&zKey[nTerm];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
}else{
*pzTerm = 0;
+ *pnTerm = 0;
*ppDoclist = 0;
*pnDoclist = 0;
}
diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c
index c467addb8a..f56aa82e8c 100644
--- a/ext/fts5/fts5_index.c
+++ b/ext/fts5/fts5_index.c
@@ -323,6 +323,9 @@ typedef struct Fts5SegWriter Fts5SegWriter;
typedef struct Fts5Structure Fts5Structure;
typedef struct Fts5StructureLevel Fts5StructureLevel;
typedef struct Fts5StructureSegment Fts5StructureSegment;
+typedef struct Fts5TokenDataIter Fts5TokenDataIter;
+typedef struct Fts5TokenDataMap Fts5TokenDataMap;
+typedef struct Fts5TombstoneArray Fts5TombstoneArray;
struct Fts5Data {
u8 *p; /* Pointer to buffer containing record */
@@ -357,6 +360,7 @@ struct Fts5Index {
/* Error state. */
int rc; /* Current error code */
+ int flushRc;
/* State used by the fts5DataXXX() functions. */
sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
@@ -365,6 +369,7 @@ struct Fts5Index {
sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
sqlite3_stmt *pIdxSelect;
+ sqlite3_stmt *pIdxNextSelect;
int nRead; /* Total number of blocks read */
sqlite3_stmt *pDeleteFromIdx;
@@ -518,8 +523,7 @@ struct Fts5SegIter {
Fts5Data *pLeaf; /* Current leaf data */
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
i64 iLeafOffset; /* Byte offset within current leaf */
- Fts5Data **apTombstone; /* Array of tombstone pages */
- int nTombstone;
+ Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
@@ -546,6 +550,15 @@ struct Fts5SegIter {
u8 bDel; /* True if the delete flag is set */
};
+/*
+** Array of tombstone pages. Reference counted.
+*/
+struct Fts5TombstoneArray {
+ int nRef; /* Number of pointers to this object */
+ int nTombstone;
+ Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+};
+
/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
@@ -590,9 +603,16 @@ struct Fts5SegIter {
** poslist:
** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
** There is no way to tell if this is populated or not.
+**
+** pColset:
+** If not NULL, points to an object containing a set of column indices.
+** Only matches that occur in one of these columns will be returned.
+** The Fts5Iter does not own the Fts5Colset object, and so it is not
+** freed when the iterator is closed - it is owned by the upper layer.
*/
struct Fts5Iter {
Fts5IndexIter base; /* Base class containing output vars */
+ Fts5TokenDataIter *pTokenDataIter;
Fts5Index *pIndex; /* Index that owns this iterator */
Fts5Buffer poslist; /* Buffer containing current poslist */
@@ -610,7 +630,6 @@ struct Fts5Iter {
Fts5SegIter aSeg[1]; /* Array of segment iterators */
};
-
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -759,11 +778,13 @@ static int fts5LeafFirstTermOff(Fts5Data *pLeaf){
/*
** Close the read-only blob handle, if it is open.
*/
-void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+static void fts5IndexCloseReader(Fts5Index *p){
if( p->pReader ){
+ int rc;
sqlite3_blob *pReader = p->pReader;
p->pReader = 0;
- sqlite3_blob_close(pReader);
+ rc = sqlite3_blob_close(pReader);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
}
}
@@ -788,7 +809,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
assert( p->pReader==0 );
p->pReader = pBlob;
if( rc!=SQLITE_OK ){
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
}
@@ -812,11 +833,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader);
- sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING;
+ int szData = (sizeof(Fts5Data) + 7) & ~7;
+ sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
if( pRet ){
pRet->nn = nByte;
- aOut = pRet->p = (u8*)&pRet[1];
+ aOut = pRet->p = (u8*)pRet + szData;
}else{
rc = SQLITE_NOMEM;
}
@@ -839,6 +861,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
}
assert( (pRet==0)==(p->rc!=SQLITE_OK) );
+ assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) );
return pRet;
}
@@ -870,9 +893,13 @@ static int fts5IndexPrepareStmt(
){
if( p->rc==SQLITE_OK ){
if( zSql ){
- p->rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
+ int rc = sqlite3_prepare_v3(p->pConfig->db, zSql, -1,
SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB,
ppStmt, 0);
+ /* If this prepare() call fails with SQLITE_ERROR, then one of the
+ ** %_idx or %_data tables has been removed or modified. Call this
+ ** corruption. */
+ p->rc = (rc==SQLITE_ERROR ? SQLITE_CORRUPT : rc);
}else{
p->rc = SQLITE_NOMEM;
}
@@ -1528,9 +1555,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}
if( iOffnn ){
- i64 iVal;
+ u64 iVal;
pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
- iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
+ iOff += fts5GetVarint(&pData->p[iOff], &iVal);
pLvl->iRowid += iVal;
pLvl->iOff = iOff;
}else{
@@ -1909,18 +1936,20 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
}
/*
-** Allocate a tombstone hash page array (pIter->apTombstone) for the
-** iterator passed as the second argument. If an OOM error occurs, leave
-** an error in the Fts5Index object.
+** Allocate a tombstone hash page array object (pIter->pTombArray) for
+** the iterator passed as the second argument. If an OOM error occurs,
+** leave an error in the Fts5Index object.
*/
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
- Fts5Data **apTomb = 0;
- apTomb = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data)*nTomb);
- if( apTomb ){
- pIter->apTombstone = apTomb;
- pIter->nTombstone = nTomb;
+ int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ Fts5TombstoneArray *pNew;
+ pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( pNew ){
+ pNew->nTombstone = nTomb;
+ pNew->nRef = 1;
+ pIter->pTombArray = pNew;
}
}
}
@@ -2162,7 +2191,7 @@ static void fts5SegIterNext_None(
if( iOffiEndofDoclist ){
/* Next entry is on the current page */
- i64 iDelta;
+ u64 iDelta;
iOff += sqlite3Fts5GetVarint(&pIter->pLeaf->p[iOff], (u64*)&iDelta);
pIter->iLeafOffset = iOff;
pIter->iRowid += iDelta;
@@ -2177,15 +2206,16 @@ static void fts5SegIterNext_None(
}else{
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList;
sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
if( pList==0 ) goto next_none_eof;
pIter->pLeaf->p = (u8*)pList;
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList;
- sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
+ sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
}
@@ -2251,11 +2281,12 @@ static void fts5SegIterNext(
}else if( pIter->pSeg==0 ){
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList = 0;
assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
}
if( pList==0 ){
fts5DataRelease(pIter->pLeaf);
@@ -2265,8 +2296,7 @@ static void fts5SegIterNext(
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList+1;
- sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
- (u8*)zTerm);
+ sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
*pbNewTerm = 1;
}
@@ -2652,7 +2682,7 @@ static void fts5SegIterSeekInit(
fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
}
- if( p->rc==SQLITE_OK && bGe==0 ){
+ if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_DESC ){
@@ -2668,7 +2698,9 @@ static void fts5SegIterSeekInit(
}
fts5SegIterSetNext(p, pIter);
- fts5SegIterAllocTombstone(p, pIter);
+ if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){
+ fts5SegIterAllocTombstone(p, pIter);
+ }
/* Either:
**
@@ -2685,6 +2717,79 @@ static void fts5SegIterSeekInit(
);
}
+
+/*
+** SQL used by fts5SegIterNextInit() to find the page to open.
+*/
+static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){
+ if( p->pIdxNextSelect==0 ){
+ Fts5Config *pConfig = p->pConfig;
+ fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlite3_mprintf(
+ "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+ "segid=? AND term>? ORDER BY term ASC LIMIT 1",
+ pConfig->zDb, pConfig->zName
+ ));
+
+ }
+ return p->pIdxNextSelect;
+}
+
+/*
+** This is similar to fts5SegIterSeekInit(), except that it initializes
+** the segment iterator to point to the first term following the page
+** with pToken/nToken on it.
+*/
+static void fts5SegIterNextInit(
+ Fts5Index *p,
+ const char *pTerm, int nTerm,
+ Fts5StructureSegment *pSeg, /* Description of segment */
+ Fts5SegIter *pIter /* Object to populate */
+){
+ int iPg = -1; /* Page of segment to open */
+ int bDlidx = 0;
+ sqlite3_stmt *pSel = 0; /* SELECT to find iPg */
+
+ pSel = fts5IdxNextStmt(p);
+ if( pSel ){
+ assert( p->rc==SQLITE_OK );
+ sqlite3_bind_int(pSel, 1, pSeg->iSegid);
+ sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC);
+
+ if( sqlite3_step(pSel)==SQLITE_ROW ){
+ i64 val = sqlite3_column_int64(pSel, 0);
+ iPg = (int)(val>>1);
+ bDlidx = (val & 0x0001);
+ }
+ p->rc = sqlite3_reset(pSel);
+ sqlite3_bind_null(pSel, 2);
+ if( p->rc ) return;
+ }
+
+ memset(pIter, 0, sizeof(*pIter));
+ pIter->pSeg = pSeg;
+ pIter->flags |= FTS5_SEGITER_ONETERM;
+ if( iPg>=0 ){
+ pIter->iLeafPgno = iPg - 1;
+ fts5SegIterNextPage(p, pIter);
+ fts5SegIterSetNext(p, pIter);
+ }
+ if( pIter->pLeaf ){
+ const u8 *a = pIter->pLeaf->p;
+ int iTermOff = 0;
+
+ pIter->iPgidxOff = pIter->pLeaf->szLeaf;
+ pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff);
+ pIter->iLeafOffset = iTermOff;
+ fts5SegIterLoadTerm(p, pIter, 0);
+ fts5SegIterLoadNPos(p, pIter);
+ if( bDlidx ) fts5SegIterLoadDlidx(p, pIter);
+
+ assert( p->rc!=SQLITE_OK ||
+ fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0
+ );
+ }
+}
+
/*
** Initialize the object pIter to point to term pTerm/nTerm within the
** in-memory hash table. If there is no such term in the hash-table, the
@@ -2711,8 +2816,7 @@ static void fts5SegIterHashInit(
const u8 *pList = 0;
p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
- sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
- n = (z ? (int)strlen((const char*)z) : 0);
+ sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList);
if( pList ){
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
if( pLeaf ){
@@ -2771,6 +2875,23 @@ static void fts5IndexFreeArray(Fts5Data **ap, int n){
}
}
+/*
+** Decrement the ref-count of the object passed as the only argument. If it
+** reaches 0, free it and its contents.
+*/
+static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){
+ if( p ){
+ p->nRef--;
+ if( p->nRef<=0 ){
+ int ii;
+ for(ii=0; iinTombstone; ii++){
+ fts5DataRelease(p->apTombstone[ii]);
+ }
+ sqlite3_free(p);
+ }
+ }
+}
+
/*
** Zero the iterator passed as the only argument.
*/
@@ -2778,7 +2899,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){
fts5BufferFree(&pIter->term);
fts5DataRelease(pIter->pLeaf);
fts5DataRelease(pIter->pNextLeaf);
- fts5IndexFreeArray(pIter->apTombstone, pIter->nTombstone);
+ fts5TombstoneArrayDelete(pIter->pTombArray);
fts5DlidxIterFree(pIter->pDlidx);
sqlite3_free(pIter->aRowidOffset);
memset(pIter, 0, sizeof(Fts5SegIter));
@@ -3023,7 +3144,6 @@ static void fts5SegIterNextFrom(
}while( p->rc==SQLITE_OK );
}
-
/*
** Free the iterator object passed as the second argument.
*/
@@ -3168,24 +3288,25 @@ static int fts5IndexTombstoneQuery(
static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
int iFirst = pIter->aFirst[1].iFirst;
Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+ Fts5TombstoneArray *pArray = pSeg->pTombArray;
- if( pSeg->pLeaf && pSeg->nTombstone ){
+ if( pSeg->pLeaf && pArray ){
/* Figure out which page the rowid might be present on. */
- int iPg = ((u64)pSeg->iRowid) % pSeg->nTombstone;
+ int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone;
assert( iPg>=0 );
/* If tombstone hash page iPg has not yet been loaded from the
** database, load it now. */
- if( pSeg->apTombstone[iPg]==0 ){
- pSeg->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
+ if( pArray->apTombstone[iPg]==0 ){
+ pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
);
- if( pSeg->apTombstone[iPg]==0 ) return 0;
+ if( pArray->apTombstone[iPg]==0 ) return 0;
}
return fts5IndexTombstoneQuery(
- pSeg->apTombstone[iPg],
- pSeg->nTombstone,
+ pArray->apTombstone[iPg],
+ pArray->nTombstone,
pSeg->iRowid
);
}
@@ -3724,6 +3845,32 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
}
}
+/*
+** All the component segment-iterators of pIter have been set up. This
+** functions finishes setup for iterator pIter itself.
+*/
+static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){
+ int iIter;
+ for(iIter=pIter->nSeg-1; iIter>0; iIter--){
+ int iEq;
+ if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){
+ Fts5SegIter *pSeg = &pIter->aSeg[iEq];
+ if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
+ fts5MultiIterAdvanced(p, pIter, iEq, iIter);
+ }
+ }
+ fts5MultiIterSetEof(pIter);
+ fts5AssertMultiIterSetup(p, pIter);
+
+ if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter))
+ || fts5MultiIterIsDeleted(pIter)
+ ){
+ fts5MultiIterNext(p, pIter, 0, 0);
+ }else if( pIter->base.bEof==0 ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ pIter->xSetOutputs(pIter, pSeg);
+ }
+}
/*
** Allocate a new Fts5Iter object.
@@ -3805,31 +3952,12 @@ static void fts5MultiIterNew(
assert( iIter==nSeg );
}
- /* If the above was successful, each component iterators now points
+ /* If the above was successful, each component iterator now points
** to the first entry in its segment. In this case initialize the
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
- for(iIter=pNew->nSeg-1; iIter>0; iIter--){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
- Fts5SegIter *pSeg = &pNew->aSeg[iEq];
- if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
- fts5MultiIterAdvanced(p, pNew, iEq, iIter);
- }
- }
- fts5MultiIterSetEof(pNew);
- fts5AssertMultiIterSetup(p, pNew);
-
- if( (pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew))
- || fts5MultiIterIsDeleted(pNew)
- ){
- fts5MultiIterNext(p, pNew, 0, 0);
- }else if( pNew->base.bEof==0 ){
- Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
- pNew->xSetOutputs(pNew, pSeg);
- }
-
+ fts5MultiIterFinishSetup(p, pNew);
}else{
fts5MultiIterFree(pNew);
*ppOut = 0;
@@ -3854,7 +3982,6 @@ static void fts5MultiIterNew2(
pNew = fts5MultiIterAlloc(p, 2);
if( pNew ){
Fts5SegIter *pIter = &pNew->aSeg[1];
-
pIter->flags = FTS5_SEGITER_ONETERM;
if( pData->szLeaf>0 ){
pIter->pLeaf = pData;
@@ -4002,6 +4129,7 @@ static void fts5IndexDiscardData(Fts5Index *p){
sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
p->nPendingRow = 0;
+ p->flushRc = SQLITE_OK;
}
p->nContentlessDelete = 0;
}
@@ -4217,7 +4345,7 @@ static void fts5WriteDlidxAppend(
}
if( pDlidx->bPrevValid ){
- iVal = iRowid - pDlidx->iPrev;
+ iVal = (u64)iRowid - (u64)pDlidx->iPrev;
}else{
i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
assert( pDlidx->buf.n==0 );
@@ -4767,6 +4895,11 @@ static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
nBest = nPercent;
}
}
+
+ /* If pLvl is already the input level to an ongoing merge, look no
+ ** further for a merge candidate. The caller should be allowed to
+ ** continue merging from pLvl first. */
+ if( pLvl->nMerge ) break;
}
}
return iRet;
@@ -4878,6 +5011,14 @@ static int fts5IndexReturn(Fts5Index *p){
return rc;
}
+/*
+** Close the read-only blob handle, if it is open.
+*/
+void sqlite3Fts5IndexCloseReader(Fts5Index *p){
+ fts5IndexCloseReader(p);
+ fts5IndexReturn(p);
+}
+
typedef struct Fts5FlushCtx Fts5FlushCtx;
struct Fts5FlushCtx {
Fts5Index *pIdx;
@@ -5335,17 +5476,38 @@ static void fts5DoSecureDelete(
** This is called as part of flushing a delete to disk in 'secure-delete'
** mode. It edits the segments within the database described by argument
** pStruct to remove the entries for term zTerm, rowid iRowid.
+**
+** Return SQLITE_OK if successful, or an SQLite error code if an error
+** has occurred. Any error code is also stored in the Fts5Index handle.
*/
-static void fts5FlushSecureDelete(
+static int fts5FlushSecureDelete(
Fts5Index *p,
Fts5Structure *pStruct,
const char *zTerm,
+ int nTerm,
i64 iRowid
){
const int f = FTS5INDEX_QUERY_SKIPHASH;
- int nTerm = (int)strlen(zTerm);
Fts5Iter *pIter = 0; /* Used to find term instance */
+ /* If the version number has not been set to SECUREDELETE, do so now. */
+ if( p->pConfig->iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE ){
+ Fts5Config *pConfig = p->pConfig;
+ sqlite3_stmt *pStmt = 0;
+ fts5IndexPrepareStmt(p, &pStmt, sqlite3_mprintf(
+ "REPLACE INTO %Q.'%q_config' VALUES ('version', %d)",
+ pConfig->zDb, pConfig->zName, FTS5_CURRENT_VERSION_SECUREDELETE
+ ));
+ if( p->rc==SQLITE_OK ){
+ int rc;
+ sqlite3_step(pStmt);
+ rc = sqlite3_finalize(pStmt);
+ if( p->rc==SQLITE_OK ) p->rc = rc;
+ pConfig->iCookie++;
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
if( fts5MultiIterEof(p, pIter)==0 ){
i64 iThis = fts5MultiIterRowid(pIter);
@@ -5363,6 +5525,7 @@ static void fts5FlushSecureDelete(
}
fts5MultiIterFree(pIter);
+ return p->rc;
}
@@ -5417,8 +5580,7 @@ static void fts5FlushOneHash(Fts5Index *p){
int nDoclist; /* Size of doclist in bytes */
/* Get the term and doclist for this entry. */
- sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- nTerm = (int)strlen(zTerm);
+ sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist);
if( bSecureDelete==0 ){
fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
if( p->rc!=SQLITE_OK ) break;
@@ -5447,8 +5609,9 @@ static void fts5FlushOneHash(Fts5Index *p){
** using fts5FlushSecureDelete(). */
if( bSecureDelete ){
if( eDetail==FTS5_DETAIL_NONE ){
- if( iOffrc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
iOff++;
continue;
@@ -5584,6 +5748,10 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
+ if( p->flushRc ){
+ p->rc = p->flushRc;
+ return;
+ }
if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
fts5FlushOneHash(p);
@@ -5592,6 +5760,8 @@ static void fts5IndexFlush(Fts5Index *p){
p->nPendingData = 0;
p->nPendingRow = 0;
p->nContentlessDelete = 0;
+ }else if( p->nPendingData || p->nContentlessDelete ){
+ p->flushRc = p->rc;
}
}
}
@@ -6071,190 +6241,527 @@ static void fts5MergePrefixLists(
*p1 = out;
}
-static void fts5SetupPrefixIter(
- Fts5Index *p, /* Index to read from */
- int bDesc, /* True for "ORDER BY rowid DESC" */
- int iIdx, /* Index to scan for data */
- u8 *pToken, /* Buffer containing prefix to match */
+
+/*
+** Iterate through a range of entries in the FTS index, invoking the xVisit
+** callback for each of them.
+**
+** Parameter pToken points to an nToken buffer containing an FTS index term
+** (i.e. a document term with the preceding 1 byte index identifier -
+** FTS5_MAIN_PREFIX or similar). If bPrefix is true, then the call visits
+** all entries for terms that have pToken/nToken as a prefix. If bPrefix
+** is false, then only entries with pToken/nToken as the entire key are
+** visited.
+**
+** If the current table is a tokendata=1 table, then if bPrefix is true then
+** each index term is treated separately. However, if bPrefix is false, then
+** all index terms corresponding to pToken/nToken are collapsed into a single
+** term before the callback is invoked.
+**
+** The callback invoked for each entry visited is specified by paramter xVisit.
+** Each time it is invoked, it is passed a pointer to the Fts5Index object,
+** a copy of the 7th paramter to this function (pCtx) and a pointer to the
+** iterator that indicates the current entry. If the current entry is the
+** first with a new term (i.e. different from that of the previous entry,
+** including the very first term), then the final two parameters are passed
+** a pointer to the term and its size in bytes, respectively. If the current
+** entry is not the first associated with its term, these two parameters
+** are passed 0.
+**
+** If parameter pColset is not NULL, then it is used to filter entries before
+** the callback is invoked.
+*/
+static int fts5VisitEntries(
+ Fts5Index *p, /* Fts5 index object */
+ Fts5Colset *pColset, /* Columns filter to apply, or NULL */
+ u8 *pToken, /* Buffer containing token */
int nToken, /* Size of buffer pToken in bytes */
- Fts5Colset *pColset, /* Restrict matches to these columns */
- Fts5Iter **ppIter /* OUT: New iterator */
+ int bPrefix, /* True for a prefix scan */
+ void (*xVisit)(Fts5Index*, void *pCtx, Fts5Iter *pIter, const u8*, int),
+ void *pCtx /* Passed as second argument to xVisit() */
){
- Fts5Structure *pStruct;
- Fts5Buffer *aBuf;
- int nBuf = 32;
- int nMerge = 1;
+ const int flags = (bPrefix ? FTS5INDEX_QUERY_SCAN : 0)
+ | FTS5INDEX_QUERY_SKIPEMPTY
+ | FTS5INDEX_QUERY_NOOUTPUT;
+ Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
+ int bNewTerm = 1;
+ Fts5Structure *pStruct = fts5StructureRead(p);
+
+ fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
+ fts5IterSetOutputCb(&p->rc, p1);
+ for( /* no-op */ ;
+ fts5MultiIterEof(p, p1)==0;
+ fts5MultiIterNext2(p, p1, &bNewTerm)
+ ){
+ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
+ int nNew = 0;
+ const u8 *pNew = 0;
- void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
- void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
- if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
- xMerge = fts5MergeRowidLists;
- xAppend = fts5AppendRowid;
- }else{
- nMerge = FTS5_MERGE_NLIST-1;
- nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
- xMerge = fts5MergePrefixLists;
- xAppend = fts5AppendPoslist;
+ p1->xSetOutputs(p1, pSeg);
+ if( p->rc ) break;
+
+ if( bNewTerm ){
+ nNew = pSeg->term.n;
+ pNew = pSeg->term.p;
+ if( nNewrc;
+}
- if( aBuf && pStruct ){
- const int flags = FTS5INDEX_QUERY_SCAN
- | FTS5INDEX_QUERY_SKIPEMPTY
- | FTS5INDEX_QUERY_NOOUTPUT;
- int i;
- i64 iLastRowid = 0;
- Fts5Iter *p1 = 0; /* Iterator used to gather data from index */
- Fts5Data *pData;
- Fts5Buffer doclist;
- int bNewTerm = 1;
- memset(&doclist, 0, sizeof(doclist));
- if( iIdx!=0 ){
- int dummy = 0;
- const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
- pToken[0] = FTS5_MAIN_PREFIX;
- fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
- fts5IterSetOutputCb(&p->rc, p1);
- for(;
- fts5MultiIterEof(p, p1)==0;
- fts5MultiIterNext2(p, p1, &dummy)
- ){
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
- p1->xSetOutputs(p1, pSeg);
- if( p1->base.nData ){
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
- iLastRowid = p1->base.iRowid;
- }
- }
- fts5MultiIterFree(p1);
+/*
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
+** array of these for each row it visits (so all iRowid fields are the same).
+** Or, for an iterator used by an "ORDER BY rank" query, it accumulates an
+** array of these for the entire query (in which case iRowid fields may take
+** a variety of values).
+**
+** Each instance in the array indicates the iterator (and therefore term)
+** associated with position iPos of rowid iRowid. This is used by the
+** xInstToken() API.
+**
+** iRowid:
+** Rowid for the current entry.
+**
+** iPos:
+** Position of current entry within row. In the usual ((iCol<<32)+iOff)
+** format (e.g. see macros FTS5_POS2COLUMN() and FTS5_POS2OFFSET()).
+**
+** iIter:
+** If the Fts5TokenDataIter iterator that the entry is part of is
+** actually an iterator (i.e. with nIter>0, not just a container for
+** Fts5TokenDataMap structures), then this variable is an index into
+** the apIter[] array. The corresponding term is that which the iterator
+** at apIter[iIter] currently points to.
+**
+** Or, if the Fts5TokenDataIter iterator is just a container object
+** (nIter==0), then iIter is an index into the term.p[] buffer where
+** the term is stored.
+**
+** nByte:
+** In the case where iIter is an index into term.p[], this variable
+** is the size of the term in bytes. If iIter is an index into apIter[],
+** this variable is unused.
+*/
+struct Fts5TokenDataMap {
+ i64 iRowid; /* Row this token is located in */
+ i64 iPos; /* Position of token */
+ int iIter; /* Iterator token was read from */
+ int nByte; /* Length of token in bytes (or 0) */
+};
+
+/*
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
+**
+** This object serves two purposes. The first is as a container for an array
+** of Fts5TokenDataMap structures, which are used to find the token required
+** when the xInstToken() API is used. This is done by the nMapAlloc, nMap and
+** aMap[] variables.
+*/
+struct Fts5TokenDataIter {
+ int nMapAlloc; /* Allocated size of aMap[] in entries */
+ int nMap; /* Number of valid entries in aMap[] */
+ Fts5TokenDataMap *aMap; /* Array of (rowid+pos -> token) mappings */
+
+ /* The following are used for prefix-queries only. */
+ Fts5Buffer terms;
+
+ /* The following are used for other full-token tokendata queries only. */
+ int nIter;
+ int nIterAlloc;
+ Fts5PoslistReader *aPoslistReader;
+ int *aPoslistToIter;
+ Fts5Iter *apIter[1];
+};
+
+/*
+** The two input arrays - a1[] and a2[] - are in sorted order. This function
+** merges the two arrays together and writes the result to output array
+** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
+**
+** Duplicate entries are copied into the output. So the size of the output
+** array is always (n1+n2) entries.
+*/
+static void fts5TokendataMerge(
+ Fts5TokenDataMap *a1, int n1, /* Input array 1 */
+ Fts5TokenDataMap *a2, int n2, /* Input array 2 */
+ Fts5TokenDataMap *aOut /* Output array */
+){
+ int i1 = 0;
+ int i2 = 0;
+
+ assert( n1>=0 && n2>=0 );
+ while( i1=n2 || (i1rc, p1);
- for( /* no-op */ ;
- fts5MultiIterEof(p, p1)==0;
- fts5MultiIterNext2(p, p1, &bNewTerm)
- ){
- Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
- int nTerm = pSeg->term.n;
- const u8 *pTerm = pSeg->term.p;
- p1->xSetOutputs(p1, pSeg);
- assert_nc( memcmp(pToken, pTerm, MIN(nToken, nTerm))<=0 );
- if( bNewTerm ){
- if( nTermrc==SQLITE_OK ){
+ if( pT->nMap==pT->nMapAlloc ){
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
+ int nAlloc = nNew * sizeof(Fts5TokenDataMap);
+ Fts5TokenDataMap *aNew;
+
+ aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nAlloc);
+ if( aNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
}
- if( p1->base.nData==0 ) continue;
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
- if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
- for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
- int i1 = i*nMerge;
- int iStore;
- assert( i1+nMerge<=nBuf );
- for(iStore=i1; iStoreaMap[pT->nMap].iRowid = iRowid;
+ pT->aMap[pT->nMap].iPos = iPos;
+ pT->aMap[pT->nMap].iIter = iIter;
+ pT->aMap[pT->nMap].nByte = nByte;
+ pT->nMap++;
+ }
+}
+
+/*
+** Sort the contents of the pT->aMap[] array.
+**
+** The sorting algorithm requries a malloc(). If this fails, an error code
+** is left in Fts5Index.rc before returning.
+*/
+static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
+ Fts5TokenDataMap *aTmp = 0;
+ int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
+
+ aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( aTmp ){
+ Fts5TokenDataMap *a1 = pT->aMap;
+ Fts5TokenDataMap *a2 = aTmp;
+ i64 nHalf;
+
+ for(nHalf=1; nHalfnMap; nHalf=nHalf*2){
+ int i1;
+ for(i1=0; i1nMap; i1+=(nHalf*2)){
+ int n1 = MIN(nHalf, pT->nMap-i1);
+ int n2 = MIN(nHalf, pT->nMap-i1-n1);
+ fts5TokendataMerge(&a1[i1], n1, &a1[i1+n1], n2, &a2[i1]);
}
+ SWAPVAL(Fts5TokenDataMap*, a1, a2);
+ }
- xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
- iLastRowid = p1->base.iRowid;
+ if( a1!=pT->aMap ){
+ memcpy(pT->aMap, a1, pT->nMap*sizeof(Fts5TokenDataMap));
}
+ sqlite3_free(aTmp);
- assert( (nBuf%nMerge)==0 );
- for(i=0; irc==SQLITE_OK ){
- xMerge(p, &doclist, nMerge, &aBuf[i]);
- }
- for(iFree=i; iFreenMap; ii++){
+ Fts5TokenDataMap *p1 = &pT->aMap[ii-1];
+ Fts5TokenDataMap *p2 = &pT->aMap[ii];
+ assert( p1->iRowidiRowid
+ || (p1->iRowid==p2->iRowid && p1->iPos<=p2->iPos)
+ );
}
}
- fts5MultiIterFree(p1);
+#endif
+ }
+}
- pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
- if( pData ){
- pData->p = (u8*)&pData[1];
- pData->nn = pData->szLeaf = doclist.n;
- if( doclist.n ) memcpy(pData->p, doclist.p, doclist.n);
- fts5MultiIterNew2(p, pData, bDesc, ppIter);
+/*
+** Delete an Fts5TokenDataIter structure and its contents.
+*/
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
+ if( pSet ){
+ int ii;
+ for(ii=0; iinIter; ii++){
+ fts5MultiIterFree(pSet->apIter[ii]);
}
- fts5BufferFree(&doclist);
+ fts5BufferFree(&pSet->terms);
+ sqlite3_free(pSet->aPoslistReader);
+ sqlite3_free(pSet->aMap);
+ sqlite3_free(pSet);
}
-
- fts5StructureRelease(pStruct);
- sqlite3_free(aBuf);
}
/*
-** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
-** to the document with rowid iRowid.
+** fts5VisitEntries() context object used by fts5SetupPrefixIterTokendata()
+** to pass data to prefixIterSetupTokendataCb().
*/
-int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
- assert( p->rc==SQLITE_OK );
+typedef struct TokendataSetupCtx TokendataSetupCtx;
+struct TokendataSetupCtx {
+ Fts5TokenDataIter *pT; /* Object being populated with mappings */
+ int iTermOff; /* Offset of current term in terms.p[] */
+ int nTermByte; /* Size of current term in bytes */
+};
- /* Allocate the hash table if it has not already been allocated */
- if( p->pHash==0 ){
- p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
- }
+/*
+** fts5VisitEntries() callback used by fts5SetupPrefixIterTokendata(). This
+** callback adds an entry to the Fts5TokenDataIter.aMap[] array for each
+** position in the current position-list. It doesn't matter that some of
+** these may be out of order - they will be sorted later.
+*/
+static void prefixIterSetupTokendataCb(
+ Fts5Index *p,
+ void *pCtx,
+ Fts5Iter *p1,
+ const u8 *pNew,
+ int nNew
+){
+ TokendataSetupCtx *pSetup = (TokendataSetupCtx*)pCtx;
+ int iPosOff = 0;
+ i64 iPos = 0;
- /* Flush the hash table to disk if required */
- if( iRowidiWriteRowid
- || (iRowid==p->iWriteRowid && p->bDelete==0)
- || (p->nPendingData > p->pConfig->nHashSize)
- ){
- fts5IndexFlush(p);
+ if( pNew ){
+ pSetup->nTermByte = nNew-1;
+ pSetup->iTermOff = pSetup->pT->terms.n;
+ fts5BufferAppendBlob(&p->rc, &pSetup->pT->terms, nNew-1, pNew+1);
}
- p->iWriteRowid = iRowid;
- p->bDelete = bDelete;
- if( bDelete==0 ){
- p->nPendingRow++;
+ while( 0==sqlite3Fts5PoslistNext64(
+ p1->base.pData, p1->base.nData, &iPosOff, &iPos
+ ) ){
+ fts5TokendataIterAppendMap(p,
+ pSetup->pT, pSetup->iTermOff, pSetup->nTermByte, p1->base.iRowid, iPos
+ );
}
- return fts5IndexReturn(p);
}
+
/*
-** Commit data to disk.
+** Context object passed by fts5SetupPrefixIter() to fts5VisitEntries().
*/
-int sqlite3Fts5IndexSync(Fts5Index *p){
- assert( p->rc==SQLITE_OK );
- fts5IndexFlush(p);
- sqlite3Fts5IndexCloseReader(p);
- return fts5IndexReturn(p);
-}
+typedef struct PrefixSetupCtx PrefixSetupCtx;
+struct PrefixSetupCtx {
+ void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
+ i64 iLastRowid;
+ int nMerge;
+ Fts5Buffer *aBuf;
+ int nBuf;
+ Fts5Buffer doclist;
+ TokendataSetupCtx *pTokendata;
+};
/*
-** Discard any data stored in the in-memory hash tables. Do not write it
-** to the database. Additionally, assume that the contents of the %_data
-** table may have changed on disk. So any in-memory caches of %_data
-** records must be invalidated.
+** fts5VisitEntries() callback used by fts5SetupPrefixIter()
*/
-int sqlite3Fts5IndexRollback(Fts5Index *p){
- sqlite3Fts5IndexCloseReader(p);
- fts5IndexDiscardData(p);
- fts5StructureInvalidate(p);
- /* assert( p->rc==SQLITE_OK ); */
- return SQLITE_OK;
-}
+static void prefixIterSetupCb(
+ Fts5Index *p,
+ void *pCtx,
+ Fts5Iter *p1,
+ const u8 *pNew,
+ int nNew
+){
+ PrefixSetupCtx *pSetup = (PrefixSetupCtx*)pCtx;
+ const int nMerge = pSetup->nMerge;
+
+ if( p1->base.nData>0 ){
+ if( p1->base.iRowid<=pSetup->iLastRowid && pSetup->doclist.n>0 ){
+ int i;
+ for(i=0; p->rc==SQLITE_OK && pSetup->doclist.n; i++){
+ int i1 = i*nMerge;
+ int iStore;
+ assert( i1+nMerge<=pSetup->nBuf );
+ for(iStore=i1; iStoreaBuf[iStore].n==0 ){
+ fts5BufferSwap(&pSetup->doclist, &pSetup->aBuf[iStore]);
+ fts5BufferZero(&pSetup->doclist);
+ break;
+ }
+ }
+ if( iStore==i1+nMerge ){
+ pSetup->xMerge(p, &pSetup->doclist, nMerge, &pSetup->aBuf[i1]);
+ for(iStore=i1; iStoreaBuf[iStore]);
+ }
+ }
+ }
+ pSetup->iLastRowid = 0;
+ }
+
+ pSetup->xAppend(
+ p, (u64)p1->base.iRowid-(u64)pSetup->iLastRowid, p1, &pSetup->doclist
+ );
+ pSetup->iLastRowid = p1->base.iRowid;
+ }
+
+ if( pSetup->pTokendata ){
+ prefixIterSetupTokendataCb(p, (void*)pSetup->pTokendata, p1, pNew, nNew);
+ }
+}
+
+static void fts5SetupPrefixIter(
+ Fts5Index *p, /* Index to read from */
+ int bDesc, /* True for "ORDER BY rowid DESC" */
+ int iIdx, /* Index to scan for data */
+ u8 *pToken, /* Buffer containing prefix to match */
+ int nToken, /* Size of buffer pToken in bytes */
+ Fts5Colset *pColset, /* Restrict matches to these columns */
+ Fts5Iter **ppIter /* OUT: New iterator */
+){
+ Fts5Structure *pStruct;
+ PrefixSetupCtx s;
+ TokendataSetupCtx s2;
+
+ memset(&s, 0, sizeof(s));
+ memset(&s2, 0, sizeof(s2));
+
+ s.nMerge = 1;
+ s.iLastRowid = 0;
+ s.nBuf = 32;
+ if( iIdx==0
+ && p->pConfig->eDetail==FTS5_DETAIL_FULL
+ && p->pConfig->bPrefixInsttoken
+ ){
+ s.pTokendata = &s2;
+ s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, sizeof(*s2.pT));
+ }
+
+ if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
+ s.xMerge = fts5MergeRowidLists;
+ s.xAppend = fts5AppendRowid;
+ }else{
+ s.nMerge = FTS5_MERGE_NLIST-1;
+ s.nBuf = s.nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
+ s.xMerge = fts5MergePrefixLists;
+ s.xAppend = fts5AppendPoslist;
+ }
+
+ s.aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*s.nBuf);
+ pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || (s.aBuf && pStruct) );
+
+ if( p->rc==SQLITE_OK ){
+ void *pCtx = (void*)&s;
+ int i;
+ Fts5Data *pData;
+
+ /* If iIdx is non-zero, then it is the number of a prefix-index for
+ ** prefixes 1 character longer than the prefix being queried for. That
+ ** index contains all the doclists required, except for the one
+ ** corresponding to the prefix itself. That one is extracted from the
+ ** main term index here. */
+ if( iIdx!=0 ){
+ pToken[0] = FTS5_MAIN_PREFIX;
+ fts5VisitEntries(p, pColset, pToken, nToken, 0, prefixIterSetupCb, pCtx);
+ }
+
+ pToken[0] = FTS5_MAIN_PREFIX + iIdx;
+ fts5VisitEntries(p, pColset, pToken, nToken, 1, prefixIterSetupCb, pCtx);
+
+ assert( (s.nBuf%s.nMerge)==0 );
+ for(i=0; irc==SQLITE_OK ){
+ s.xMerge(p, &s.doclist, s.nMerge, &s.aBuf[i]);
+ }
+ for(iFree=i; iFreerc!=SQLITE_OK );
+ if( pData ){
+ pData->p = (u8*)&pData[1];
+ pData->nn = pData->szLeaf = s.doclist.n;
+ if( s.doclist.n ) memcpy(pData->p, s.doclist.p, s.doclist.n);
+ fts5MultiIterNew2(p, pData, bDesc, ppIter);
+ }
+
+ assert( (*ppIter)!=0 || p->rc!=SQLITE_OK );
+ if( p->rc==SQLITE_OK && s.pTokendata ){
+ fts5TokendataIterSortMap(p, s2.pT);
+ (*ppIter)->pTokenDataIter = s2.pT;
+ s2.pT = 0;
+ }
+ }
+
+ fts5TokendataIterDelete(s2.pT);
+ fts5BufferFree(&s.doclist);
+ fts5StructureRelease(pStruct);
+ sqlite3_free(s.aBuf);
+}
+
+
+/*
+** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
+** to the document with rowid iRowid.
+*/
+int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
+ assert( p->rc==SQLITE_OK );
+
+ /* Allocate the hash table if it has not already been allocated */
+ if( p->pHash==0 ){
+ p->rc = sqlite3Fts5HashNew(p->pConfig, &p->pHash, &p->nPendingData);
+ }
+
+ /* Flush the hash table to disk if required */
+ if( iRowidiWriteRowid
+ || (iRowid==p->iWriteRowid && p->bDelete==0)
+ || (p->nPendingData > p->pConfig->nHashSize)
+ ){
+ fts5IndexFlush(p);
+ }
+
+ p->iWriteRowid = iRowid;
+ p->bDelete = bDelete;
+ if( bDelete==0 ){
+ p->nPendingRow++;
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
+** Commit data to disk.
+*/
+int sqlite3Fts5IndexSync(Fts5Index *p){
+ assert( p->rc==SQLITE_OK );
+ fts5IndexFlush(p);
+ fts5IndexCloseReader(p);
+ return fts5IndexReturn(p);
+}
+
+/*
+** Discard any data stored in the in-memory hash tables. Do not write it
+** to the database. Additionally, assume that the contents of the %_data
+** table may have changed on disk. So any in-memory caches of %_data
+** records must be invalidated.
+*/
+int sqlite3Fts5IndexRollback(Fts5Index *p){
+ fts5IndexCloseReader(p);
+ fts5IndexDiscardData(p);
+ fts5StructureInvalidate(p);
+ return fts5IndexReturn(p);
+}
/*
** The %_data table is completely empty when this function is called. This
@@ -6332,6 +6839,7 @@ int sqlite3Fts5IndexClose(Fts5Index *p){
sqlite3_finalize(p->pIdxWriter);
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
+ sqlite3_finalize(p->pIdxNextSelect);
sqlite3_finalize(p->pDataVersion);
sqlite3_finalize(p->pDeleteFromIdx);
sqlite3Fts5HashFree(p->pHash);
@@ -6427,6 +6935,387 @@ int sqlite3Fts5IndexWrite(
return rc;
}
+/*
+** pToken points to a buffer of size nToken bytes containing a search
+** term, including the index number at the start, used on a tokendata=1
+** table. This function returns true if the term in buffer pBuf matches
+** token pToken/nToken.
+*/
+static int fts5IsTokendataPrefix(
+ Fts5Buffer *pBuf,
+ const u8 *pToken,
+ int nToken
+){
+ return (
+ pBuf->n>=nToken
+ && 0==memcmp(pBuf->p, pToken, nToken)
+ && (pBuf->n==nToken || pBuf->p[nToken]==0x00)
+ );
+}
+
+/*
+** Ensure the segment-iterator passed as the only argument points to EOF.
+*/
+static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
+ fts5DataRelease(pSeg->pLeaf);
+ pSeg->pLeaf = 0;
+}
+
+static void fts5IterClose(Fts5IndexIter *pIndexIter){
+ if( pIndexIter ){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
+ fts5MultiIterFree(pIter);
+ fts5IndexCloseReader(pIndex);
+ }
+}
+
+/*
+** This function appends iterator pAppend to Fts5TokenDataIter pIn and
+** returns the result.
+*/
+static Fts5TokenDataIter *fts5AppendTokendataIter(
+ Fts5Index *p, /* Index object (for error code) */
+ Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */
+ Fts5Iter *pAppend /* Append this iterator */
+){
+ Fts5TokenDataIter *pRet = pIn;
+
+ if( p->rc==SQLITE_OK ){
+ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
+ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
+ int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
+
+ if( pNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ if( pIn==0 ) memset(pNew, 0, nByte);
+ pRet = pNew;
+ pNew->nIterAlloc = nAlloc;
+ }
+ }
+ }
+ if( p->rc ){
+ fts5IterClose((Fts5IndexIter*)pAppend);
+ }else{
+ pRet->apIter[pRet->nIter++] = pAppend;
+ }
+ assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
+
+ return pRet;
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function sets the iterator output
+** variables (pIter->base.*) according to the contents of the current
+** row.
+*/
+static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
+ int ii;
+ int nHit = 0;
+ i64 iRowid = SMALLEST_INT64;
+ int iMin = 0;
+
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+
+ pIter->base.nData = 0;
+ pIter->base.pData = 0;
+
+ for(ii=0; iinIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0 ){
+ if( nHit==0 || p->base.iRowidbase.iRowid;
+ nHit = 1;
+ pIter->base.pData = p->base.pData;
+ pIter->base.nData = p->base.nData;
+ iMin = ii;
+ }else if( p->base.iRowid==iRowid ){
+ nHit++;
+ }
+ }
+ }
+
+ if( nHit==0 ){
+ pIter->base.bEof = 1;
+ }else{
+ int eDetail = pIter->pIndex->pConfig->eDetail;
+ pIter->base.bEof = 0;
+ pIter->base.iRowid = iRowid;
+
+ if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, 0, iRowid, -1);
+ }else
+ if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
+ int nReader = 0;
+ int nByte = 0;
+ i64 iPrev = 0;
+
+ /* Allocate array of iterators if they are not already allocated. */
+ if( pT->aPoslistReader==0 ){
+ pT->aPoslistReader = (Fts5PoslistReader*)sqlite3Fts5MallocZero(
+ &pIter->pIndex->rc,
+ pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int))
+ );
+ if( pT->aPoslistReader==0 ) return;
+ pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter];
+ }
+
+ /* Populate an iterator for each poslist that will be merged */
+ for(ii=0; iinIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( iRowid==p->base.iRowid ){
+ pT->aPoslistToIter[nReader] = ii;
+ sqlite3Fts5PoslistReaderInit(
+ p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++]
+ );
+ nByte += p->base.nData;
+ }
+ }
+
+ /* Ensure the output buffer is large enough */
+ if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){
+ return;
+ }
+
+ /* Ensure the token-mapping is large enough */
+ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
+ int nNew = (pT->nMapAlloc + nByte) * 2;
+ Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc(
+ pT->aMap, nNew*sizeof(Fts5TokenDataMap)
+ );
+ if( aNew==0 ){
+ pIter->pIndex->rc = SQLITE_NOMEM;
+ return;
+ }
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pIter->poslist.n = 0;
+
+ while( 1 ){
+ i64 iMinPos = LARGEST_INT64;
+
+ /* Find smallest position */
+ iMin = 0;
+ for(ii=0; iiaPoslistReader[ii];
+ if( pReader->bEof==0 ){
+ if( pReader->iPosiPos;
+ iMin = ii;
+ }
+ }
+ }
+
+ /* If all readers were at EOF, break out of the loop. */
+ if( iMinPos==LARGEST_INT64 ) break;
+
+ sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos);
+ sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]);
+
+ if( eDetail==FTS5_DETAIL_FULL ){
+ pT->aMap[pT->nMap].iPos = iMinPos;
+ pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin];
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->nMap++;
+ }
+ }
+
+ pIter->base.pData = pIter->poslist.p;
+ pIter->base.nData = pIter->poslist.n;
+ }
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function advances the iterator. If
+** argument bFrom is false, then the iterator is advanced to the next
+** entry. Or, if bFrom is true, it is advanced to the first entry with
+** a rowid of iFrom or greater.
+*/
+static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
+ int ii;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *pIndex = pIter->pIndex;
+
+ for(ii=0; iinIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0
+ && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowidbase.bEof==0
+ && p->base.iRowidrc==SQLITE_OK
+ ){
+ fts5MultiIterNext(pIndex, p, 0, 0);
+ }
+ }
+ }
+
+ if( pIndex->rc==SQLITE_OK ){
+ fts5IterSetOutputsTokendata(pIter);
+ }
+}
+
+/*
+** If the segment-iterator passed as the first argument is at EOF, then
+** set pIter->term to a copy of buffer pTerm.
+*/
+static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){
+ if( pIter && pIter->aSeg[0].pLeaf==0 ){
+ fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p);
+ }
+}
+
+/*
+** This function sets up an iterator to use for a non-prefix query on a
+** tokendata=1 table.
+*/
+static Fts5Iter *fts5SetupTokendataIter(
+ Fts5Index *p, /* FTS index to query */
+ const u8 *pToken, /* Buffer containing query term */
+ int nToken, /* Size of buffer pToken in bytes */
+ Fts5Colset *pColset /* Colset to filter on */
+){
+ Fts5Iter *pRet = 0;
+ Fts5TokenDataIter *pSet = 0;
+ Fts5Structure *pStruct = 0;
+ const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN;
+
+ Fts5Buffer bSeek = {0, 0, 0};
+ Fts5Buffer *pSmall = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
+
+ while( p->rc==SQLITE_OK ){
+ Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
+ Fts5Iter *pNew = 0;
+ Fts5SegIter *pNewIter = 0;
+ Fts5SegIter *pPrevIter = 0;
+
+ int iLvl, iSeg, ii;
+
+ pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
+ if( pSmall ){
+ fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
+ fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
+ }else{
+ fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
+ }
+ if( p->rc ){
+ fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ pNewIter = &pNew->aSeg[0];
+ pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
+ for(iLvl=0; iLvlnLevel; iLvl++){
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ int bDone = 0;
+
+ if( pPrevIter ){
+ if( fts5BufferCompare(pSmall, &pPrevIter->term) ){
+ memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter));
+ memset(pPrevIter, 0, sizeof(Fts5SegIter));
+ bDone = 1;
+ }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){
+ fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter);
+ bDone = 1;
+ }
+ }
+
+ if( bDone==0 ){
+ fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter);
+ }
+
+ if( pPrevIter ){
+ if( pPrevIter->pTombArray ){
+ pNewIter->pTombArray = pPrevIter->pTombArray;
+ pNewIter->pTombArray->nRef++;
+ }
+ }else{
+ fts5SegIterAllocTombstone(p, pNewIter);
+ }
+
+ pNewIter++;
+ if( pPrevIter ) pPrevIter++;
+ if( p->rc ) break;
+ }
+ }
+ fts5TokendataSetTermIfEof(pPrev, pSmall);
+
+ pNew->bSkipEmpty = 1;
+ pNew->pColset = pColset;
+ fts5IterSetOutputCb(&p->rc, pNew);
+
+ /* Loop through all segments in the new iterator. Find the smallest
+ ** term that any segment-iterator points to. Iterator pNew will be
+ ** used for this term. Also, set any iterator that points to a term that
+ ** does not match pToken/nToken to point to EOF */
+ pSmall = 0;
+ for(ii=0; iinSeg; ii++){
+ Fts5SegIter *pII = &pNew->aSeg[ii];
+ if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){
+ fts5SegIterSetEOF(pII);
+ }
+ if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){
+ pSmall = &pII->term;
+ }
+ }
+
+ /* If pSmall is still NULL at this point, then the new iterator does
+ ** not point to any terms that match the query. So delete it and break
+ ** out of the loop - all required iterators have been collected. */
+ if( pSmall==0 ){
+ fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ /* Append this iterator to the set and continue. */
+ pSet = fts5AppendTokendataIter(p, pSet, pNew);
+ }
+
+ if( p->rc==SQLITE_OK && pSet ){
+ int ii;
+ for(ii=0; iinIter; ii++){
+ Fts5Iter *pIter = pSet->apIter[ii];
+ int iSeg;
+ for(iSeg=0; iSegnSeg; iSeg++){
+ pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM;
+ }
+ fts5MultiIterFinishSetup(p, pIter);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pRet = fts5MultiIterAlloc(p, 0);
+ }
+ if( pRet ){
+ pRet->nSeg = 0;
+ pRet->pTokenDataIter = pSet;
+ if( pSet ){
+ fts5IterSetOutputsTokendata(pRet);
+ }else{
+ pRet->base.bEof = 1;
+ }
+ }else{
+ fts5TokendataIterDelete(pSet);
+ }
+
+ fts5StructureRelease(pStruct);
+ fts5BufferFree(&bSeek);
+ return pRet;
+}
+
/*
** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
@@ -6448,8 +7337,19 @@ int sqlite3Fts5IndexQuery(
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
+ int bTokendata = pConfig->bTokendata;
+ assert( buf.p!=0 );
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
+ /* The NOTOKENDATA flag is set when each token in a tokendata=1 table
+ ** should be treated individually, instead of merging all those with
+ ** a common prefix into a single entry. This is used, for example, by
+ ** queries performed as part of an integrity-check, or by the fts5vocab
+ ** module. */
+ if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
+ bTokendata = 0;
+ }
+
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
@@ -6475,7 +7375,10 @@ int sqlite3Fts5IndexQuery(
}
}
- if( iIdx<=pConfig->nPrefix ){
+ if( bTokendata && iIdx==0 ){
+ buf.p[0] = FTS5_MAIN_PREFIX;
+ pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
+ }else if( iIdx<=pConfig->nPrefix ){
/* Straight index lookup */
Fts5Structure *pStruct = fts5StructureRead(p);
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -6486,7 +7389,7 @@ int sqlite3Fts5IndexQuery(
fts5StructureRelease(pStruct);
}
}else{
- /* Scan multiple terms in the main index */
+ /* Scan multiple terms in the main index for a prefix query. */
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
if( pRet==0 ){
@@ -6502,9 +7405,9 @@ int sqlite3Fts5IndexQuery(
}
if( p->rc ){
- sqlite3Fts5IterClose((Fts5IndexIter*)pRet);
+ fts5IterClose((Fts5IndexIter*)pRet);
pRet = 0;
- sqlite3Fts5IndexCloseReader(p);
+ fts5IndexCloseReader(p);
}
*ppIter = (Fts5IndexIter*)pRet;
@@ -6522,7 +7425,12 @@ int sqlite3Fts5IndexQuery(
int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
assert( pIter->pIndex->rc==SQLITE_OK );
- fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ if( pIter->nSeg==0 ){
+ assert( pIter->pTokenDataIter );
+ fts5TokendataIterNext(pIter, 0, 0);
+ }else{
+ fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -6555,7 +7463,12 @@ int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
*/
int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ if( pIter->nSeg==0 ){
+ assert( pIter->pTokenDataIter );
+ fts5TokendataIterNext(pIter, 1, iMatch);
+ }else{
+ fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -6570,15 +7483,183 @@ const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
return (z ? &z[1] : 0);
}
+/*
+** pIter is a prefix query. This function populates pIter->pTokenDataIter
+** with an Fts5TokenDataIter object containing mappings for all rows
+** matched by the query.
+*/
+static int fts5SetupPrefixIterTokendata(
+ Fts5Iter *pIter,
+ const char *pToken, /* Token prefix to search for */
+ int nToken /* Size of pToken in bytes */
+){
+ Fts5Index *p = pIter->pIndex;
+ Fts5Buffer token = {0, 0, 0};
+ TokendataSetupCtx ctx;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ fts5BufferGrow(&p->rc, &token, nToken+1);
+ assert( token.p!=0 || p->rc!=SQLITE_OK );
+ ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*ctx.pT));
+
+ if( p->rc==SQLITE_OK ){
+
+ /* Fill in the token prefix to search for */
+ token.p[0] = FTS5_MAIN_PREFIX;
+ memcpy(&token.p[1], pToken, nToken);
+ token.n = nToken+1;
+
+ fts5VisitEntries(
+ p, 0, token.p, token.n, 1, prefixIterSetupTokendataCb, (void*)&ctx
+ );
+
+ fts5TokendataIterSortMap(p, ctx.pT);
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pIter->pTokenDataIter = ctx.pT;
+ }else{
+ fts5TokendataIterDelete(ctx.pT);
+ }
+ fts5BufferFree(&token);
+
+ return fts5IndexReturn(p);
+}
+
+/*
+** This is used by xInstToken() to access the token at offset iOff, column
+** iCol of row iRowid. The token is returned via output variables *ppOut
+** and *pnOut. The iterator passed as the first argument must be a tokendata=1
+** iterator (pIter->pTokenDataIter!=0).
+**
+** pToken/nToken:
+*/
+int sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
+ Fts5TokenDataMap *aMap = 0;
+ int i1 = 0;
+ int i2 = 0;
+ int iTest = 0;
+
+ assert( pT || (pToken && pIter->nSeg>0) );
+ if( pT==0 ){
+ int rc = fts5SetupPrefixIterTokendata(pIter, pToken, nToken);
+ if( rc!=SQLITE_OK ) return rc;
+ pT = pIter->pTokenDataIter;
+ }
+
+ i2 = pT->nMap;
+ aMap = pT->aMap;
+
+ while( i2>i1 ){
+ iTest = (i1 + i2) / 2;
+
+ if( aMap[iTest].iRowidiRowid ){
+ i2 = iTest;
+ }else{
+ if( aMap[iTest].iPosiPos ){
+ i2 = iTest;
+ }else{
+ break;
+ }
+ }
+ }
+
+ if( i2>i1 ){
+ if( pIter->nSeg==0 ){
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
+ *pnOut = pMap->aSeg[0].term.n-1;
+ }else{
+ Fts5TokenDataMap *p = &aMap[iTest];
+ *ppOut = (const char*)&pT->terms.p[p->iIter];
+ *pnOut = aMap[iTest].nByte;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Clear any existing entries from the token-map associated with the
+** iterator passed as the only argument.
+*/
+void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ if( pIter && pIter->pTokenDataIter
+ && (pIter->nSeg==0 || pIter->pIndex->pConfig->eDetail!=FTS5_DETAIL_FULL)
+ ){
+ pIter->pTokenDataIter->nMap = 0;
+ }
+}
+
+/*
+** Set a token-mapping for the iterator passed as the first argument. This
+** is used in detail=column or detail=none mode when a token is requested
+** using the xInstToken() API. In this case the caller tokenizers the
+** current row and configures the token-mapping via multiple calls to this
+** function.
+*/
+int sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid, int iCol, int iOff
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *p = pIter->pIndex;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
+
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
+ assert( pIter->pTokenDataIter || pIter->nSeg>0 );
+ if( pIter->nSeg>0 ){
+ /* This is a prefix term iterator. */
+ if( pT==0 ){
+ pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc, sizeof(*pT));
+ pIter->pTokenDataIter = pT;
+ }
+ if( pT ){
+ fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
+ fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
+ }
+ }else{
+ int ii;
+ for(ii=0; iinIter; ii++){
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
+ }
+ if( iinIter ){
+ fts5TokendataIterAppendMap(p, pT, ii, 0, iRowid, iPos);
+ }
+ }
+ return fts5IndexReturn(p);
+}
+
/*
** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
*/
void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
- Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- Fts5Index *pIndex = pIter->pIndex;
- fts5MultiIterFree(pIter);
- sqlite3Fts5IndexCloseReader(pIndex);
+ Fts5Index *pIndex = ((Fts5Iter*)pIndexIter)->pIndex;
+ fts5IterClose(pIndexIter);
+ fts5IndexReturn(pIndex);
}
}
@@ -7084,7 +8165,9 @@ static int fts5QueryCksum(
int eDetail = p->pConfig->eDetail;
u64 cksum = *pCksum;
Fts5IndexIter *pIter = 0;
- int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
+ int rc = sqlite3Fts5IndexQuery(
+ p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter
+ );
while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){
i64 rowid = pIter->iRowid;
@@ -7106,7 +8189,7 @@ static int fts5QueryCksum(
rc = sqlite3Fts5IterNext(pIter);
}
}
- sqlite3Fts5IterClose(pIter);
+ fts5IterClose(pIter);
*pCksum = cksum;
return rc;
@@ -7251,7 +8334,7 @@ static void fts5IndexIntegrityCheckEmpty(
}
static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
- int iTermOff = 0;
+ i64 iTermOff = 0;
int ii;
Fts5Buffer buf1 = {0,0,0};
@@ -7260,7 +8343,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
ii = pLeaf->szLeaf;
while( iinn && p->rc==SQLITE_OK ){
int res;
- int iOff;
+ i64 iOff;
int nIncr;
ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
@@ -7782,6 +8865,24 @@ static void fts5DecodeRowidList(
}
#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){
+ int ii;
+ fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1);
+ if( *pRc==SQLITE_OK ){
+ for(ii=0; iin; ii++){
+ if( pTerm->p[ii]==0x00 ){
+ pBuf->p[pBuf->n++] = '\\';
+ pBuf->p[pBuf->n++] = '0';
+ }else{
+ pBuf->p[pBuf->n++] = pTerm->p[ii];
+ }
+ }
+ pBuf->p[pBuf->n] = 0x00;
+ }
+}
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_decode().
@@ -7889,9 +8990,8 @@ static void fts5DecodeFunction(
iOff += fts5GetVarint32(&a[iOff], nAppend);
term.n = nKeep;
fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += nAppend;
/* Figure out where the doclist for this term ends */
@@ -7999,9 +9099,8 @@ static void fts5DecodeFunction(
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
iOff += nByte;
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
}
@@ -8099,7 +9198,7 @@ static int fts5structConnectMethod(
/*
** We must have a single struct=? constraint that will be passed through
-** into the xFilter method. If there is no valid stmt=? constraint,
+** into the xFilter method. If there is no valid struct=? constraint,
** then return an SQLITE_CONSTRAINT error.
*/
static int fts5structBestIndexMethod(
diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c
index 6e86ca5951..9f504bb3a3 100644
--- a/ext/fts5/fts5_main.c
+++ b/ext/fts5/fts5_main.c
@@ -83,8 +83,18 @@ struct Fts5Global {
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
Fts5TokenizerModule *pDfltTok; /* Default tokenizer module */
Fts5Cursor *pCsr; /* First in list of all open cursors */
+ u32 aLocaleHdr[4];
};
+/*
+** Size of header on fts5_locale() values. And macro to access a buffer
+** containing a copy of the header from an Fts5Config pointer.
+*/
+#define FTS5_LOCALE_HDR_SIZE ((int)sizeof( ((Fts5Global*)0)->aLocaleHdr ))
+#define FTS5_LOCALE_HDR(pConfig) ((const u8*)(pConfig->pGlobal->aLocaleHdr))
+
+#define FTS5_INSTTOKEN_SUBTYPE 73
+
/*
** Each auxiliary function registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
@@ -103,11 +113,28 @@ struct Fts5Auxiliary {
** Each tokenizer module registered with the FTS5 module is represented
** by an object of the following type. All such objects are stored as part
** of the Fts5Global.pTok list.
+**
+** bV2Native:
+** True if the tokenizer was registered using xCreateTokenizer_v2(), false
+** for xCreateTokenizer(). If this variable is true, then x2 is populated
+** with the routines as supplied by the caller and x1 contains synthesized
+** wrapper routines. In this case the user-data pointer passed to
+** x1.xCreate should be a pointer to the Fts5TokenizerModule structure,
+** not a copy of pUserData.
+**
+** Of course, if bV2Native is false, then x1 contains the real routines and
+** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule
+** object should be passed to x2.xCreate.
+**
+** The synthesized wrapper routines are necessary for xFindTokenizer(_v2)
+** calls.
*/
struct Fts5TokenizerModule {
char *zName; /* Name of tokenizer */
void *pUserData; /* User pointer passed to xCreate() */
- fts5_tokenizer x; /* Tokenizer functions */
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
void (*xDestroy)(void*); /* Destructor function */
Fts5TokenizerModule *pNext; /* Next registered tokenizer module */
};
@@ -118,7 +145,7 @@ struct Fts5FullTable {
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
int iSavepoint; /* Successful xSavepoint()+1 */
- int bInSavepoint;
+
#ifdef SQLITE_DEBUG
struct Fts5TransactionState ts;
#endif
@@ -195,7 +222,7 @@ struct Fts5Cursor {
Fts5Auxiliary *pAux; /* Currently executing extension function */
Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */
- /* Cache used by auxiliary functions xInst() and xInstCount() */
+ /* Cache used by auxiliary API functions xInst() and xInstCount() */
Fts5PoslistReader *aInstIter; /* One for each phrase */
int nInstAlloc; /* Size of aInst[] array (entries / 3) */
int nInstCount; /* Number of phrase instances */
@@ -306,10 +333,16 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
#endif
/*
-** Return true if pTab is a contentless table.
+** Return true if pTab is a contentless table. If parameter bIncludeUnindexed
+** is true, this includes contentless tables that store UNINDEXED columns
+** only.
*/
-static int fts5IsContentless(Fts5FullTable *pTab){
- return pTab->p.pConfig->eContent==FTS5_CONTENT_NONE;
+static int fts5IsContentless(Fts5FullTable *pTab, int bIncludeUnindexed){
+ int eContent = pTab->p.pConfig->eContent;
+ return (
+ eContent==FTS5_CONTENT_NONE
+ || (bIncludeUnindexed && eContent==FTS5_CONTENT_UNINDEXED)
+ );
}
/*
@@ -377,8 +410,12 @@ static int fts5InitVtab(
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
}
if( rc==SQLITE_OK ){
+ pConfig->pzErrmsg = pzErr;
pTab->p.pConfig = pConfig;
pTab->pGlobal = pGlobal;
+ if( bCreate || sqlite3Fts5TokenizerPreload(&pConfig->t) ){
+ rc = sqlite3Fts5LoadTokenizer(pConfig);
+ }
}
/* Open the index sub-system */
@@ -400,11 +437,7 @@ static int fts5InitVtab(
/* Load the initial configuration */
if( rc==SQLITE_OK ){
- assert( pConfig->pzErrmsg==0 );
- pConfig->pzErrmsg = pzErr;
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
- sqlite3Fts5IndexRollback(pTab->p.pIndex);
- pConfig->pzErrmsg = 0;
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie-1);
}
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -414,6 +447,7 @@ static int fts5InitVtab(
rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
+ if( pConfig ) pConfig->pzErrmsg = 0;
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -481,10 +515,10 @@ static int fts5UsePatternMatch(
){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
- if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
+ if( pConfig->t.ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1;
}
- if( pConfig->ePattern==FTS5_PATTERN_LIKE
+ if( pConfig->t.ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){
return 1;
@@ -531,10 +565,10 @@ static int fts5UsePatternMatch(
** This function ensures that there is at most one "r" or "=". And that if
** there exists an "=" then there is no "<" or ">".
**
-** Costs are assigned as follows:
+** If an unusable MATCH operator is present in the WHERE clause, then
+** SQLITE_CONSTRAINT is returned.
**
-** a) If an unusable MATCH operator is present in the WHERE clause, the
-** cost is unconditionally set to 1e50 (a really big number).
+** Costs are assigned as follows:
**
** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows:
@@ -567,7 +601,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int bSeenEq = 0;
int bSeenGt = 0;
int bSeenLt = 0;
- int bSeenMatch = 0;
+ int nSeenMatch = 0;
int bSeenRank = 0;
@@ -598,18 +632,16 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* A MATCH operator or equivalent */
if( p->usable==0 || iCol<0 ){
/* As there exists an unusable MATCH constraint this is an
- ** unusable plan. Set a prohibitively high cost. */
- pInfo->estimatedCost = 1e50;
- assert( iIdxStr < pInfo->nConstraint*6 + 1 );
+ ** unusable plan. Return SQLITE_CONSTRAINT. */
idxStr[iIdxStr] = 0;
- return SQLITE_OK;
+ return SQLITE_CONSTRAINT;
}else{
if( iCol==nCol+1 ){
if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r';
bSeenRank = 1;
- }else if( iCol>=0 ){
- bSeenMatch = 1;
+ }else{
+ nSeenMatch++;
idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]);
@@ -626,6 +658,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' );
+ nSeenMatch++;
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '=';
bSeenEq = 1;
@@ -656,12 +689,15 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
idxStr[iIdxStr] = '\0';
- /* Set idxFlags flags for the ORDER BY clause */
+ /* Set idxFlags flags for the ORDER BY clause
+ **
+ ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
+ */
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
- if( iSort==(pConfig->nCol+1) && bSeenMatch ){
+ if( iSort==(pConfig->nCol+1) && nSeenMatch>0 ){
idxFlags |= FTS5_BI_ORDER_RANK;
- }else if( iSort==-1 ){
+ }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID;
}
if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
@@ -674,14 +710,17 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){
- pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0;
- if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
+ pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
+ if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
}else if( bSeenLt && bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0;
+ pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
}else if( bSeenLt || bSeenGt ){
- pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0;
+ pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
}else{
- pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0;
+ pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
+ }
+ for(i=1; iestimatedCost *= 0.4;
}
pInfo->idxNum = idxFlags;
@@ -913,6 +952,16 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
+ /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
+ ** clear any token mappings accumulated at the fts5_index.c level. In
+ ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
+ ** we need to retain the mappings for the entire query. */
+ if( pCsr->ePlan==FTS5_PLAN_MATCH
+ && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
+ ){
+ sqlite3Fts5ExprClearTokens(pCsr->pExpr);
+ }
+
if( pCsr->ePlan<3 ){
int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
@@ -947,6 +996,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
}
}else{
rc = SQLITE_OK;
+ CsrFlagSet(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
}
break;
}
@@ -976,7 +1026,7 @@ static int fts5PrepareStatement(
rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
SQLITE_PREPARE_PERSISTENT, &pRet, 0);
if( rc!=SQLITE_OK ){
- *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
+ sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db));
}
sqlite3_free(zSql);
}
@@ -1200,6 +1250,145 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
return iDefault;
}
+/*
+** Set the error message on the virtual table passed as the first argument.
+*/
+static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
+ va_list ap; /* ... printf arguments */
+ va_start(ap, zFormat);
+ sqlite3_free(p->p.base.zErrMsg);
+ p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+}
+
+/*
+** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale
+** specified by pLocale/nLocale. The buffer indicated by pLocale must remain
+** valid until after the final call to sqlite3Fts5Tokenize() that will use
+** the locale.
+*/
+static void sqlite3Fts5SetLocale(
+ Fts5Config *pConfig,
+ const char *zLocale,
+ int nLocale
+){
+ Fts5TokenizerConfig *pT = &pConfig->t;
+ pT->pLocale = zLocale;
+ pT->nLocale = nLocale;
+}
+
+/*
+** Clear any locale configured by an earlier call to sqlite3Fts5SetLocale().
+*/
+void sqlite3Fts5ClearLocale(Fts5Config *pConfig){
+ sqlite3Fts5SetLocale(pConfig, 0, 0);
+}
+
+/*
+** Return true if the value passed as the only argument is an
+** fts5_locale() value.
+*/
+int sqlite3Fts5IsLocaleValue(Fts5Config *pConfig, sqlite3_value *pVal){
+ int ret = 0;
+ if( sqlite3_value_type(pVal)==SQLITE_BLOB ){
+ /* Call sqlite3_value_bytes() after sqlite3_value_blob() in this case.
+ ** If the blob was created using zeroblob(), then sqlite3_value_blob()
+ ** may call malloc(). If this malloc() fails, then the values returned
+ ** by both value_blob() and value_bytes() will be 0. If value_bytes() were
+ ** called first, then the NULL pointer returned by value_blob() might
+ ** be dereferenced. */
+ const u8 *pBlob = sqlite3_value_blob(pVal);
+ int nBlob = sqlite3_value_bytes(pVal);
+ if( nBlob>FTS5_LOCALE_HDR_SIZE
+ && 0==memcmp(pBlob, FTS5_LOCALE_HDR(pConfig), FTS5_LOCALE_HDR_SIZE)
+ ){
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+/*
+** Value pVal is guaranteed to be an fts5_locale() value, according to
+** sqlite3Fts5IsLocaleValue(). This function extracts the text and locale
+** from the value and returns them separately.
+**
+** If successful, SQLITE_OK is returned and (*ppText) and (*ppLoc) set
+** to point to buffers containing the text and locale, as utf-8,
+** respectively. In this case output parameters (*pnText) and (*pnLoc) are
+** set to the sizes in bytes of these two buffers.
+**
+** Or, if an error occurs, then an SQLite error code is returned. The final
+** value of the four output parameters is undefined in this case.
+*/
+int sqlite3Fts5DecodeLocaleValue(
+ sqlite3_value *pVal,
+ const char **ppText,
+ int *pnText,
+ const char **ppLoc,
+ int *pnLoc
+){
+ const char *p = sqlite3_value_blob(pVal);
+ int n = sqlite3_value_bytes(pVal);
+ int nLoc = 0;
+
+ assert( sqlite3_value_type(pVal)==SQLITE_BLOB );
+ assert( n>FTS5_LOCALE_HDR_SIZE );
+
+ for(nLoc=FTS5_LOCALE_HDR_SIZE; p[nLoc]; nLoc++){
+ if( nLoc==(n-1) ){
+ return SQLITE_MISMATCH;
+ }
+ }
+ *ppLoc = &p[FTS5_LOCALE_HDR_SIZE];
+ *pnLoc = nLoc - FTS5_LOCALE_HDR_SIZE;
+
+ *ppText = &p[nLoc+1];
+ *pnText = n - nLoc - 1;
+ return SQLITE_OK;
+}
+
+/*
+** Argument pVal is the text of a full-text search expression. It may or
+** may not have been wrapped by fts5_locale(). This function extracts
+** the text of the expression, and sets output variable (*pzText) to
+** point to a nul-terminated buffer containing the expression.
+**
+** If pVal was an fts5_locale() value, then sqlite3Fts5SetLocale() is called
+** to set the tokenizer to use the specified locale.
+**
+** If output variable (*pbFreeAndReset) is set to true, then the caller
+** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer
+** locale, and (b) call sqlite3_free() to free (*pzText).
+*/
+static int fts5ExtractExprText(
+ Fts5Config *pConfig, /* Fts5 configuration */
+ sqlite3_value *pVal, /* Value to extract expression text from */
+ char **pzText, /* OUT: nul-terminated buffer of text */
+ int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */
+){
+ int rc = SQLITE_OK;
+
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, pText);
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ }
+ *pbFreeAndReset = 1;
+ }else{
+ *pzText = (char*)sqlite3_value_text(pVal);
+ *pbFreeAndReset = 0;
+ }
+
+ return rc;
+}
+
+
/*
** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional
@@ -1230,17 +1419,12 @@ static int fts5FilterMethod(
sqlite3_value *pRowidGe = 0; /* rowid >= ? expression (or NULL) */
int iCol; /* Column on LHS of MATCH operator */
char **pzErrmsg = pConfig->pzErrmsg;
+ int bPrefixInsttoken = pConfig->bPrefixInsttoken;
int i;
int iIdxStr = 0;
Fts5Expr *pExpr = 0;
- if( pConfig->bLock ){
- pTab->p.base.zErrMsg = sqlite3_mprintf(
- "recursively defined fts5 content table"
- );
- return SQLITE_ERROR;
- }
-
+ assert( pConfig->bLock==0 );
if( pCsr->ePlan ){
fts5FreeCursorComponents(pCsr);
memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr));
@@ -1264,8 +1448,17 @@ static int fts5FilterMethod(
pRank = apVal[i];
break;
case 'M': {
- const char *zText = (const char*)sqlite3_value_text(apVal[i]);
+ char *zText = 0;
+ int bFreeAndReset = 0;
+ int bInternal = 0;
+
+ rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset);
+ if( rc!=SQLITE_OK ) goto filter_out;
if( zText==0 ) zText = "";
+ if( sqlite3_value_subtype(apVal[i])==FTS5_INSTTOKEN_SUBTYPE ){
+ pConfig->bPrefixInsttoken = 1;
+ }
+
iCol = 0;
do{
iCol = iCol*10 + (idxStr[iIdxStr]-'0');
@@ -1277,7 +1470,7 @@ static int fts5FilterMethod(
** indicates that the MATCH expression is not a full text query,
** but a request for an internal parameter. */
rc = fts5SpecialMatch(pTab, pCsr, &zText[1]);
- goto filter_out;
+ bInternal = 1;
}else{
char **pzErr = &pTab->p.base.zErrMsg;
rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
@@ -1285,9 +1478,15 @@ static int fts5FilterMethod(
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
pExpr = 0;
}
- if( rc!=SQLITE_OK ) goto filter_out;
}
+ if( bFreeAndReset ){
+ sqlite3_free(zText);
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ if( bInternal || rc!=SQLITE_OK ) goto filter_out;
+
break;
}
case 'L':
@@ -1375,9 +1574,7 @@ static int fts5FilterMethod(
}
}
}else if( pConfig->zContent==0 ){
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "%s: table does not support scanning", pConfig->zName
- );
+ fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName);
rc = SQLITE_ERROR;
}else{
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
@@ -1401,6 +1598,7 @@ static int fts5FilterMethod(
filter_out:
sqlite3Fts5ExprFree(pExpr);
pConfig->pzErrmsg = pzErrmsg;
+ pConfig->bPrefixInsttoken = bPrefixInsttoken;
return rc;
}
@@ -1420,9 +1618,13 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
assert( pCsr->ePlan==FTS5_PLAN_MATCH
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|| pCsr->ePlan==FTS5_PLAN_SOURCE
+ || pCsr->ePlan==FTS5_PLAN_SCAN
+ || pCsr->ePlan==FTS5_PLAN_ROWID
);
if( pCsr->pSorter ){
return pCsr->pSorter->iRowid;
+ }else if( pCsr->ePlan>=FTS5_PLAN_SCAN ){
+ return sqlite3_column_int64(pCsr->pStmt, 0);
}else{
return sqlite3Fts5ExprRowid(pCsr->pExpr);
}
@@ -1439,25 +1641,16 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
int ePlan = pCsr->ePlan;
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
- switch( ePlan ){
- case FTS5_PLAN_SPECIAL:
- *pRowid = 0;
- break;
-
- case FTS5_PLAN_SOURCE:
- case FTS5_PLAN_MATCH:
- case FTS5_PLAN_SORTED_MATCH:
- *pRowid = fts5CursorRowid(pCsr);
- break;
-
- default:
- *pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
- break;
+ if( ePlan==FTS5_PLAN_SPECIAL ){
+ *pRowid = 0;
+ }else{
+ *pRowid = fts5CursorRowid(pCsr);
}
return SQLITE_OK;
}
+
/*
** If the cursor requires seeking (bSeekRequired flag is set), seek it.
** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
@@ -1494,8 +1687,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT;
+ fts5SetVtabError((Fts5FullTable*)pTab,
+ "fts5: missing row %lld from content table %s",
+ fts5CursorRowid(pCsr),
+ pTab->pConfig->zContent
+ );
}else if( pTab->pConfig->pzErrmsg ){
- *pTab->pConfig->pzErrmsg = sqlite3_mprintf(
+ fts5SetVtabError((Fts5FullTable*)pTab,
"%s", sqlite3_errmsg(pTab->pConfig->db)
);
}
@@ -1504,14 +1702,6 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
return rc;
}
-static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
- va_list ap; /* ... printf arguments */
- va_start(ap, zFormat);
- assert( p->p.base.zErrMsg==0 );
- p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
- va_end(ap);
-}
-
/*
** This function is called to handle an FTS INSERT command. In other words,
** an INSERT statement of the form:
@@ -1549,7 +1739,7 @@ static int fts5SpecialInsert(
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
+ if( fts5IsContentless(pTab, 1) ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
@@ -1573,7 +1763,10 @@ static int fts5SpecialInsert(
}else if( 0==sqlite3_stricmp("flush", zCmd) ){
rc = sqlite3Fts5FlushToDisk(&pTab->p);
}else{
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
}
@@ -1602,7 +1795,7 @@ static int fts5SpecialDelete(
int eType1 = sqlite3_value_type(apVal[1]);
if( eType1==SQLITE_INTEGER ){
sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
}
return rc;
}
@@ -1615,7 +1808,7 @@ static void fts5StorageInsert(
){
int rc = *pRc;
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, piRowid);
+ rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, 0, apVal, piRowid);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal, *piRowid);
@@ -1623,6 +1816,67 @@ static void fts5StorageInsert(
*pRc = rc;
}
+/*
+**
+** This function is called when the user attempts an UPDATE on a contentless
+** table. Parameter bRowidModified is true if the UPDATE statement modifies
+** the rowid value. Parameter apVal[] contains the new values for each user
+** defined column of the fts5 table. pConfig is the configuration object of the
+** table being updated (guaranteed to be contentless). The contentless_delete=1
+** and contentless_unindexed=1 options may or may not be set.
+**
+** This function returns SQLITE_OK if the UPDATE can go ahead, or an SQLite
+** error code if it cannot. In this case an error message is also loaded into
+** pConfig. Output parameter (*pbContent) is set to true if the caller should
+** update the %_content table only - not the FTS index or any other shadow
+** table. This occurs when an UPDATE modifies only UNINDEXED columns of the
+** table.
+**
+** An UPDATE may proceed if:
+**
+** * The only columns modified are UNINDEXED columns, or
+**
+** * The contentless_delete=1 option was specified and all of the indexed
+** columns (not a subset) have been modified.
+*/
+static int fts5ContentlessUpdate(
+ Fts5Config *pConfig,
+ sqlite3_value **apVal,
+ int bRowidModified,
+ int *pbContent
+){
+ int ii;
+ int bSeenIndex = 0; /* Have seen modified indexed column */
+ int bSeenIndexNC = 0; /* Have seen unmodified indexed column */
+ int rc = SQLITE_OK;
+
+ for(ii=0; iinCol; ii++){
+ if( pConfig->abUnindexed[ii]==0 ){
+ if( sqlite3_value_nochange(apVal[ii]) ){
+ bSeenIndexNC++;
+ }else{
+ bSeenIndex++;
+ }
+ }
+ }
+
+ if( bSeenIndex==0 && bRowidModified==0 ){
+ *pbContent = 1;
+ }else{
+ if( bSeenIndexNC || pConfig->bContentlessDelete==0 ){
+ rc = SQLITE_ERROR;
+ sqlite3Fts5ConfigErrmsg(pConfig,
+ (pConfig->bContentlessDelete ?
+ "%s a subset of columns on fts5 contentless-delete table: %s" :
+ "%s contentless fts5 table: %s")
+ , "cannot UPDATE", pConfig->zName
+ );
+ }
+ }
+
+ return rc;
+}
+
/*
** This function is the implementation of the xUpdate callback used by
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
@@ -1647,7 +1901,6 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
- int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -1659,7 +1912,7 @@ static int fts5UpdateMethod(
);
assert( pTab->p.pConfig->pzErrmsg==0 );
if( pConfig->pgsz==0 ){
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlite3Fts5ConfigLoad(pTab->p.pConfig, pTab->p.pConfig->iCookie);
if( rc!=SQLITE_OK ) return rc;
}
@@ -1708,88 +1961,104 @@ static int fts5UpdateMethod(
assert( eType0==SQLITE_INTEGER || eType0==SQLITE_NULL );
assert( nArg!=1 || eType0==SQLITE_INTEGER );
- /* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. Except - they are both supported if the CREATE
- ** VIRTUAL TABLE statement contained "contentless_delete=1". */
- if( eType0==SQLITE_INTEGER
- && pConfig->eContent==FTS5_CONTENT_NONE
- && pConfig->bContentlessDelete==0
- ){
- pTab->p.base.zErrMsg = sqlite3_mprintf(
- "cannot %s contentless fts5 table: %s",
- (nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
- );
- rc = SQLITE_ERROR;
- }
-
/* DELETE */
- else if( nArg==1 ){
- i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
- bUpdateOrDelete = 1;
+ if( nArg==1 ){
+ /* It is only possible to DELETE from a contentless table if the
+ ** contentless_delete=1 flag is set. */
+ if( fts5IsContentless(pTab, 1) && pConfig->bContentlessDelete==0 ){
+ fts5SetVtabError(pTab,
+ "cannot DELETE from contentless fts5 table: %s", pConfig->zName
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
+ }
}
/* INSERT or UPDATE */
else{
int eType1 = sqlite3_value_numeric_type(apVal[1]);
- if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
- rc = SQLITE_MISMATCH;
+ /* It is an error to write an fts5_locale() value to a table without
+ ** the locale=1 option. */
+ if( pConfig->bLocale==0 ){
+ int ii;
+ for(ii=0; iinCol; ii++){
+ sqlite3_value *pVal = apVal[ii+2];
+ if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ fts5SetVtabError(pTab, "fts5_locale() requires locale=1");
+ rc = SQLITE_MISMATCH;
+ goto update_out;
+ }
+ }
}
- else if( eType0!=SQLITE_INTEGER ){
+ if( eType0!=SQLITE_INTEGER ){
/* An INSERT statement. If the conflict-mode is REPLACE, first remove
** the current entry (if any). */
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
- bUpdateOrDelete = 1;
+ rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
/* UPDATE */
else{
+ Fts5Storage *pStorage = pTab->pStorage;
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
- if( eType1==SQLITE_INTEGER && iOld!=iNew ){
+ int bContent = 0; /* Content only update */
+
+ /* If this is a contentless table (including contentless_unindexed=1
+ ** tables), check if the UPDATE may proceed. */
+ if( fts5IsContentless(pTab, 1) ){
+ rc = fts5ContentlessUpdate(pConfig, &apVal[2], iOld!=iNew, &bContent);
+ if( rc!=SQLITE_OK ) goto update_out;
+ }
+
+ if( eType1!=SQLITE_INTEGER ){
+ rc = SQLITE_MISMATCH;
+ }else if( iOld!=iNew ){
+ assert( bContent==0 );
if( eConflict==SQLITE_REPLACE ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iNew, 0, 0);
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}else{
- rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 0, apVal, pRowid);
}
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 0);
}
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageIndexInsert(pStorage, apVal, *pRowid);
+ }
+ }
+ }else if( bContent ){
+ /* This occurs when an UPDATE on a contentless table affects *only*
+ ** UNINDEXED columns. This is a no-op for contentless_unindexed=0
+ ** tables, or a write to the %_content table only for =1 tables. */
+ assert( fts5IsContentless(pTab, 1) );
+ rc = sqlite3Fts5StorageFindDeleteRow(pStorage, iOld);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5StorageContentInsert(pStorage, 1, apVal, pRowid);
}
}else{
- rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
+ rc = sqlite3Fts5StorageDelete(pStorage, iOld, 0, 1);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
- bUpdateOrDelete = 1;
+ sqlite3Fts5StorageReleaseDeleteRow(pStorage);
}
}
}
- if( rc==SQLITE_OK
- && bUpdateOrDelete
- && pConfig->bSecureDelete
- && pConfig->iVersion==FTS5_CURRENT_VERSION
- ){
- rc = sqlite3Fts5StorageConfigValue(
- pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
- );
- if( rc==SQLITE_OK ){
- pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
- }
- }
-
+ update_out:
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -1811,9 +2080,11 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
** Implementation of xBegin() method.
*/
static int fts5BeginMethod(sqlite3_vtab *pVtab){
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
- fts5NewTransaction((Fts5FullTable*)pVtab);
- return SQLITE_OK;
+ int rc = fts5NewTransaction((Fts5FullTable*)pVtab);
+ if( rc==SQLITE_OK ){
+ fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
+ }
+ return rc;
}
/*
@@ -1836,6 +2107,7 @@ static int fts5RollbackMethod(sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+ pTab->p.pConfig->pgsz = 0;
return rc;
}
@@ -1867,17 +2139,40 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow);
}
-static int fts5ApiTokenize(
+/*
+** Implementation of xTokenize_v2() API.
+*/
+static int fts5ApiTokenize_v2(
Fts5Context *pCtx,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
void *pUserData,
int (*xToken)(void*, int, const char*, int, int, int)
){
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
- return sqlite3Fts5Tokenize(
- pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
+ int rc = SQLITE_OK;
+
+ sqlite3Fts5SetLocale(pTab->pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pTab->pConfig,
+ FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken
);
+ sqlite3Fts5SetLocale(pTab->pConfig, 0, 0);
+
+ return rc;
+}
+
+/*
+** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0
+** passed as the locale.
+*/
+static int fts5ApiTokenize(
+ Fts5Context *pCtx,
+ const char *pText, int nText,
+ void *pUserData,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken);
}
static int fts5ApiPhraseCount(Fts5Context *pCtx){
@@ -1890,6 +2185,49 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
return sqlite3Fts5ExprPhraseSize(pCsr->pExpr, iPhrase);
}
+/*
+** Argument pStmt is an SQL statement of the type used by Fts5Cursor. This
+** function extracts the text value of column iCol of the current row.
+** Additionally, if there is an associated locale, it invokes
+** sqlite3Fts5SetLocale() to configure the tokenizer. In all cases the caller
+** should invoke sqlite3Fts5ClearLocale() to clear the locale at some point
+** after this function returns.
+**
+** If successful, (*ppText) is set to point to a buffer containing the text
+** value as utf-8 and SQLITE_OK returned. (*pnText) is set to the size of that
+** buffer in bytes. It is not guaranteed to be nul-terminated. If an error
+** occurs, an SQLite error code is returned. The final values of the two
+** output parameters are undefined in this case.
+*/
+static int fts5TextFromStmt(
+ Fts5Config *pConfig,
+ sqlite3_stmt *pStmt,
+ int iCol,
+ const char **ppText,
+ int *pnText
+){
+ sqlite3_value *pVal = sqlite3_column_value(pStmt, iCol+1);
+ const char *pLoc = 0;
+ int nLoc = 0;
+ int rc = SQLITE_OK;
+
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, ppText, pnText, &pLoc, &nLoc);
+ }else{
+ *ppText = (const char*)sqlite3_value_text(pVal);
+ *pnText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ pLoc = (const char*)sqlite3_column_text(pStmt, iCol+1+pConfig->nCol);
+ nLoc = sqlite3_column_bytes(pStmt, iCol+1+pConfig->nCol);
+ }
+ }
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ return rc;
+}
+
static int fts5ApiColumnText(
Fts5Context *pCtx,
int iCol,
@@ -1898,46 +2236,69 @@ static int fts5ApiColumnText(
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
- || pCsr->ePlan==FTS5_PLAN_SPECIAL
- ){
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
+ if( iCol<0 || iCol>=pTab->pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab), 0) ){
*pz = 0;
*pn = 0;
}else{
rc = fts5SeekCursor(pCsr, 0);
if( rc==SQLITE_OK ){
- *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1);
- *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
+ rc = fts5TextFromStmt(pTab->pConfig, pCsr->pStmt, iCol, pz, pn);
+ sqlite3Fts5ClearLocale(pTab->pConfig);
}
}
return rc;
}
+/*
+** This is called by various API functions - xInst, xPhraseFirst,
+** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase
+** of the current row. This function works for both detail=full tables (in
+** which case the position-list was read from the fts index) or for other
+** detail= modes if the row content is available.
+*/
static int fts5CsrPoslist(
- Fts5Cursor *pCsr,
- int iPhrase,
- const u8 **pa,
- int *pn
+ Fts5Cursor *pCsr, /* Fts5 cursor object */
+ int iPhrase, /* Phrase to find position list for */
+ const u8 **pa, /* OUT: Pointer to position list buffer */
+ int *pn /* OUT: Size of (*pa) in bytes */
){
Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
int rc = SQLITE_OK;
int bLive = (pCsr->pSorter==0);
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
-
+ if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
+ rc = SQLITE_RANGE;
+ }else if( pConfig->eDetail!=FTS5_DETAIL_FULL
+ && fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ ){
+ *pa = 0;
+ *pn = 0;
+ return SQLITE_OK;
+ }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
+
aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive);
if( aPopulator==0 ) rc = SQLITE_NOMEM;
+ if( rc==SQLITE_OK ){
+ rc = fts5SeekCursor(pCsr, 0);
+ }
for(i=0; inCol && rc==SQLITE_OK; i++){
- int n; const char *z;
- rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n);
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ExprPopulatePoslists(
pConfig, pCsr->pExpr, aPopulator, i, z, n
);
}
+ sqlite3Fts5ClearLocale(pConfig);
}
sqlite3_free(aPopulator);
@@ -1948,13 +2309,18 @@ static int fts5CsrPoslist(
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
}
- if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- *pn = pSorter->aIdx[iPhrase] - i1;
- *pa = &pSorter->aPoslist[i1];
+ if( rc==SQLITE_OK ){
+ if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
+ Fts5Sorter *pSorter = pCsr->pSorter;
+ int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
+ *pn = pSorter->aIdx[iPhrase] - i1;
+ *pa = &pSorter->aPoslist[i1];
+ }else{
+ *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ }
}else{
- *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ *pa = 0;
+ *pn = 0;
}
return rc;
@@ -2025,7 +2391,8 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
aInst[0] = iBest;
aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos);
aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos);
- if( aInst[1]<0 || aInst[1]>=nCol ){
+ assert( aInst[1]>=0 );
+ if( aInst[1]>=nCol ){
rc = FTS5_CORRUPT;
break;
}
@@ -2063,12 +2430,6 @@ static int fts5ApiInst(
){
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
rc = SQLITE_RANGE;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 2];
- *piOff = -1;
-#endif
}else{
*piPhrase = pCsr->aInst[iIdx*3];
*piCol = pCsr->aInst[iIdx*3 + 1];
@@ -2109,7 +2470,7 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
if( pConfig->bColumnsize ){
i64 iRowid = fts5CursorRowid(pCsr);
rc = sqlite3Fts5StorageDocsize(pTab->pStorage, iRowid, pCsr->aColumnSize);
- }else if( pConfig->zContent==0 ){
+ }else if( !pConfig->zContent || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
int i;
for(i=0; inCol; i++){
if( pConfig->abUnindexed[i]==0 ){
@@ -2118,17 +2479,19 @@ static int fts5ApiColumnSize(Fts5Context *pCtx, int iCol, int *pnToken){
}
}else{
int i;
+ rc = fts5SeekCursor(pCsr, 0);
for(i=0; rc==SQLITE_OK && inCol; i++){
if( pConfig->abUnindexed[i]==0 ){
- const char *z; int n;
- void *p = (void*)(&pCsr->aColumnSize[i]);
+ const char *z = 0;
+ int n = 0;
pCsr->aColumnSize[i] = 0;
- rc = fts5ApiColumnText(pCtx, i, &z, &n);
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, i, &z, &n);
if( rc==SQLITE_OK ){
- rc = sqlite3Fts5Tokenize(
- pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX,
+ z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb
);
}
+ sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -2208,11 +2571,10 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
}
static void fts5ApiPhraseNext(
- Fts5Context *pUnused,
+ Fts5Context *pCtx,
Fts5PhraseIter *pIter,
int *piCol, int *piOff
){
- UNUSED_PARAM(pUnused);
if( pIter->a>=pIter->b ){
*piCol = -1;
*piOff = -1;
@@ -2220,8 +2582,12 @@ static void fts5ApiPhraseNext(
int iVal;
pIter->a += fts5GetVarint32(pIter->a, iVal);
if( iVal==1 ){
+ /* Avoid returning a (*piCol) value that is too large for the table,
+ ** even if the position-list is corrupt. The caller might not be
+ ** expecting it. */
+ int nCol = ((Fts5Table*)(((Fts5Cursor*)pCtx)->base.pVtab))->pConfig->nCol;
pIter->a += fts5GetVarint32(pIter->a, iVal);
- *piCol = iVal;
+ *piCol = (iVal>=nCol ? nCol-1 : iVal);
*piOff = 0;
pIter->a += fts5GetVarint32(pIter->a, iVal);
}
@@ -2323,13 +2689,96 @@ static int fts5ApiPhraseFirstColumn(
return rc;
}
+/*
+** xQueryToken() API implemenetation.
+*/
+static int fts5ApiQueryToken(
+ Fts5Context* pCtx,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
+}
+
+/*
+** xInstToken() API implemenetation.
+*/
+static int fts5ApiInstToken(
+ Fts5Context *pCtx,
+ int iIdx,
+ int iToken,
+ const char **ppOut, int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ int rc = SQLITE_OK;
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
+ ){
+ if( iIdx<0 || iIdx>=pCsr->nInstCount ){
+ rc = SQLITE_RANGE;
+ }else{
+ int iPhrase = pCsr->aInst[iIdx*3];
+ int iCol = pCsr->aInst[iIdx*3 + 1];
+ int iOff = pCsr->aInst[iIdx*3 + 2];
+ i64 iRowid = fts5CursorRowid(pCsr);
+ rc = sqlite3Fts5ExprInstToken(
+ pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
+ );
+ }
+ }
+ return rc;
+}
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
+/*
+** The xColumnLocale() API.
+*/
+static int fts5ApiColumnLocale(
+ Fts5Context *pCtx,
+ int iCol,
+ const char **pzLocale,
+ int *pnLocale
+){
+ int rc = SQLITE_OK;
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig;
+
+ *pzLocale = 0;
+ *pnLocale = 0;
+
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
+ if( iCol<0 || iCol>=pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if(
+ pConfig->abUnindexed[iCol]==0
+ && 0==fts5IsContentless((Fts5FullTable*)pCsr->base.pVtab, 1)
+ && pConfig->bLocale
+ ){
+ rc = fts5SeekCursor(pCsr, 0);
+ if( rc==SQLITE_OK ){
+ const char *zDummy = 0;
+ int nDummy = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &zDummy, &nDummy);
+ if( rc==SQLITE_OK ){
+ *pzLocale = pConfig->t.pLocale;
+ *pnLocale = pConfig->t.nLocale;
+ }
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+ }
+
+ return rc;
+}
+
static const Fts5ExtensionApi sFts5Api = {
- 2, /* iVersion */
+ 4, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
@@ -2349,6 +2798,10 @@ static const Fts5ExtensionApi sFts5Api = {
fts5ApiPhraseNext,
fts5ApiPhraseFirstColumn,
fts5ApiPhraseNextColumn,
+ fts5ApiQueryToken,
+ fts5ApiInstToken,
+ fts5ApiColumnLocale,
+ fts5ApiTokenize_v2
};
/*
@@ -2399,6 +2852,7 @@ static void fts5ApiInvoke(
sqlite3_value **argv
){
assert( pCsr->pAux==0 );
+ assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL );
pCsr->pAux = pAux;
pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv);
pCsr->pAux = 0;
@@ -2412,6 +2866,21 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
return pCsr;
}
+/*
+** Parameter zFmt is a printf() style formatting string. This function
+** formats it using the trailing arguments and returns the result as
+** an error message to the context passed as the first argument.
+*/
+static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){
+ char *zErr = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zErr = sqlite3_vmprintf(zFmt, ap);
+ sqlite3_result_error(pCtx, zErr, -1);
+ sqlite3_free(zErr);
+ va_end(ap);
+}
+
static void fts5ApiCallback(
sqlite3_context *context,
int argc,
@@ -2427,12 +2896,13 @@ static void fts5ApiCallback(
iCsrId = sqlite3_value_int64(argv[0]);
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
- if( pCsr==0 || pCsr->ePlan==0 ){
- char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
- sqlite3_result_error(context, zErr, -1);
- sqlite3_free(zErr);
+ if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){
+ fts5ResultError(context, "no such cursor: %lld", iCsrId);
}else{
+ sqlite3_vtab *pTab = pCsr->base.pVtab;
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
+ sqlite3_free(pTab->zErrMsg);
+ pTab->zErrMsg = 0;
}
}
@@ -2550,8 +3020,8 @@ static int fts5ColumnMethod(
** auxiliary function. */
sqlite3_result_int64(pCtx, pCsr->iCsrId);
}else if( iCol==pConfig->nCol+1 ){
-
/* The value of the "rank" column. */
+
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
fts5PoslistBlob(pCtx, pCsr);
}else if(
@@ -2562,20 +3032,32 @@ static int fts5ColumnMethod(
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
}
}
- }else if( !fts5IsContentless(pTab) ){
- pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- rc = fts5SeekCursor(pCsr, 1);
- if( rc==SQLITE_OK ){
- sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
+ }else{
+ if( !sqlite3_vtab_nochange(pCtx) && pConfig->eContent!=FTS5_CONTENT_NONE ){
+ pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
+ rc = fts5SeekCursor(pCsr, 1);
+ if( rc==SQLITE_OK ){
+ sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
+ if( pConfig->bLocale
+ && pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ const char *z = 0;
+ int n = 0;
+ rc = fts5TextFromStmt(pConfig, pCsr->pStmt, iCol, &z, &n);
+ if( rc==SQLITE_OK ){
+ sqlite3_result_text(pCtx, z, n, SQLITE_TRANSIENT);
+ }
+ sqlite3Fts5ClearLocale(pConfig);
+ }else{
+ sqlite3_result_value(pCtx, pVal);
+ }
+ }
+
+ pConfig->pzErrmsg = 0;
}
- pConfig->pzErrmsg = 0;
- }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
- char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
- "columns on fts5 contentless-delete table: %s", pConfig->zName
- );
- sqlite3_result_error(pCtx, zErr, -1);
- sqlite3_free(zErr);
}
+
return rc;
}
@@ -2615,9 +3097,7 @@ static int fts5RenameMethod(
){
int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- pTab->bInSavepoint = 1;
rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
- pTab->bInSavepoint = 0;
return rc;
}
@@ -2634,26 +3114,12 @@ int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
int rc = SQLITE_OK;
- char *zSql = 0;
- fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
- if( pTab->bInSavepoint==0 ){
- zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
- pTab->p.pConfig->zDb, pTab->p.pConfig->zName, pTab->p.pConfig->zName
- );
- if( zSql ){
- pTab->bInSavepoint = 1;
- rc = sqlite3_exec(pTab->p.pConfig->db, zSql, 0, 0, 0);
- pTab->bInSavepoint = 0;
- sqlite3_free(zSql);
- }else{
- rc = SQLITE_NOMEM;
- }
- if( rc==SQLITE_OK ){
- pTab->iSavepoint = iSavepoint+1;
- }
+ fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+ rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
}
-
return rc;
}
@@ -2685,8 +3151,8 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
- pTab->p.pConfig->pgsz = 0;
if( (iSavepoint+1)<=pTab->iSavepoint ){
+ pTab->p.pConfig->pgsz = 0;
rc = sqlite3Fts5StorageRollback(pTab->pStorage);
}
return rc;
@@ -2731,47 +3197,210 @@ static int fts5CreateAux(
}
/*
-** Register a new tokenizer. This is the implementation of the
-** fts5_api.xCreateTokenizer() method.
+** This function is used by xCreateTokenizer_v2() and xCreateTokenizer().
+** It allocates and partially populates a new Fts5TokenizerModule object.
+** The new object is already linked into the Fts5Global context before
+** returning.
+**
+** If successful, SQLITE_OK is returned and a pointer to the new
+** Fts5TokenizerModule object returned via output parameter (*ppNew). All
+** that is required is for the caller to fill in the methods in
+** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native
+** as appropriate.
+**
+** If an error occurs, an SQLite error code is returned and the final value
+** of (*ppNew) undefined.
*/
-static int fts5CreateTokenizer(
- fts5_api *pApi, /* Global context (one per db handle) */
+static int fts5NewTokenizerModule(
+ Fts5Global *pGlobal, /* Global context (one per db handle) */
const char *zName, /* Name of new function */
void *pUserData, /* User data for aux. function */
- fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
- void(*xDestroy)(void*) /* Destructor for pUserData */
+ void(*xDestroy)(void*), /* Destructor for pUserData */
+ Fts5TokenizerModule **ppNew
){
- Fts5Global *pGlobal = (Fts5Global*)pApi;
- Fts5TokenizerModule *pNew;
- sqlite3_int64 nName; /* Size of zName and its \0 terminator */
- sqlite3_int64 nByte; /* Bytes of space to allocate */
int rc = SQLITE_OK;
+ Fts5TokenizerModule *pNew;
+ sqlite3_int64 nName; /* Size of zName and its \0 terminator */
+ sqlite3_int64 nByte; /* Bytes of space to allocate */
nName = strlen(zName) + 1;
nByte = sizeof(Fts5TokenizerModule) + nName;
- pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte);
+ *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte);
if( pNew ){
- memset(pNew, 0, (size_t)nByte);
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName);
pNew->pUserData = pUserData;
- pNew->x = *pTokenizer;
pNew->xDestroy = xDestroy;
pNew->pNext = pGlobal->pTok;
pGlobal->pTok = pNew;
if( pNew->pNext==0 ){
pGlobal->pDfltTok = pNew;
}
+ }
+
+ return rc;
+}
+
+/*
+** An instance of this type is used as the Fts5Tokenizer object for
+** wrapper tokenizers - those that provide access to a v1 tokenizer via
+** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer
+** via the fts5_tokenizer API.
+*/
+typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer;
+struct Fts5VtoVTokenizer {
+ int bV2Native; /* True if v2 native tokenizer */
+ fts5_tokenizer x1; /* Tokenizer functions */
+ fts5_tokenizer_v2 x2; /* V2 tokenizer functions */
+ Fts5Tokenizer *pReal;
+};
+
+/*
+** Create a wrapper tokenizer. The context argument pCtx points to the
+** Fts5TokenizerModule object.
+*/
+static int fts5VtoVCreate(
+ void *pCtx,
+ const char **azArg,
+ int nArg,
+ Fts5Tokenizer **ppOut
+){
+ Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx;
+ Fts5VtoVTokenizer *pNew = 0;
+ int rc = SQLITE_OK;
+
+ pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ if( rc==SQLITE_OK ){
+ pNew->x1 = pMod->x1;
+ pNew->x2 = pMod->x2;
+ pNew->bV2Native = pMod->bV2Native;
+ if( pMod->bV2Native ){
+ rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }else{
+ rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal);
+ }
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pNew);
+ pNew = 0;
+ }
+ }
+
+ *ppOut = (Fts5Tokenizer*)pNew;
+ return rc;
+}
+
+/*
+** Delete an Fts5VtoVTokenizer wrapper tokenizer.
+*/
+static void fts5VtoVDelete(Fts5Tokenizer *pTok){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ if( p ){
+ if( p->bV2Native ){
+ p->x2.xDelete(p->pReal);
+ }else{
+ p->x1.xDelete(p->pReal);
+ }
+ sqlite3_free(p);
+ }
+}
+
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v1 interface
+** (no support for locales).
+*/
+static int fts5V1toV2Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native );
+ return p->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken);
+}
+
+/*
+** xTokenizer method for a wrapper tokenizer that offers the v2 interface
+** (with locale support).
+*/
+static int fts5V2toV1Tokenize(
+ Fts5Tokenizer *pTok,
+ void *pCtx, int flags,
+ const char *pText, int nText,
+ const char *pLocale, int nLocale,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok;
+ assert( p->bV2Native==0 );
+ UNUSED_PARAM2(pLocale,nLocale);
+ return p->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken);
+}
+
+/*
+** Register a new tokenizer. This is the implementation of the
+** fts5_api.xCreateTokenizer_v2() method.
+*/
+static int fts5CreateTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5Global *pGlobal = (Fts5Global*)pApi;
+ int rc = SQLITE_OK;
+
+ if( pTokenizer->iVersion>2 ){
+ rc = SQLITE_ERROR;
}else{
- rc = SQLITE_NOMEM;
+ Fts5TokenizerModule *pNew = 0;
+ rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew);
+ if( pNew ){
+ pNew->x2 = *pTokenizer;
+ pNew->bV2Native = 1;
+ pNew->x1.xCreate = fts5VtoVCreate;
+ pNew->x1.xTokenize = fts5V1toV2Tokenize;
+ pNew->x1.xDelete = fts5VtoVDelete;
+ }
}
return rc;
}
+/*
+** The fts5_api.xCreateTokenizer() method.
+*/
+static int fts5CreateTokenizer(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of new function */
+ void *pUserData, /* User data for aux. function */
+ fts5_tokenizer *pTokenizer, /* Tokenizer implementation */
+ void(*xDestroy)(void*) /* Destructor for pUserData */
+){
+ Fts5TokenizerModule *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = fts5NewTokenizerModule(
+ (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew
+ );
+ if( pNew ){
+ pNew->x1 = *pTokenizer;
+ pNew->x2.xCreate = fts5VtoVCreate;
+ pNew->x2.xTokenize = fts5V2toV1Tokenize;
+ pNew->x2.xDelete = fts5VtoVDelete;
+ }
+ return rc;
+}
+
+/*
+** Search the global context passed as the first argument for a tokenizer
+** module named zName. If found, return a pointer to the Fts5TokenizerModule
+** object. Otherwise, return NULL.
+*/
static Fts5TokenizerModule *fts5LocateTokenizer(
- Fts5Global *pGlobal,
- const char *zName
+ Fts5Global *pGlobal, /* Global (one per db handle) object */
+ const char *zName /* Name of tokenizer module to find */
){
Fts5TokenizerModule *pMod = 0;
@@ -2786,6 +3415,36 @@ static Fts5TokenizerModule *fts5LocateTokenizer(
return pMod;
}
+/*
+** Find a tokenizer. This is the implementation of the
+** fts5_api.xFindTokenizer_v2() method.
+*/
+static int fts5FindTokenizer_v2(
+ fts5_api *pApi, /* Global context (one per db handle) */
+ const char *zName, /* Name of tokenizer */
+ void **ppUserData,
+ fts5_tokenizer_v2 **ppTokenizer /* Populate this object */
+){
+ int rc = SQLITE_OK;
+ Fts5TokenizerModule *pMod;
+
+ pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
+ if( pMod ){
+ if( pMod->bV2Native ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *ppTokenizer = &pMod->x2;
+ }else{
+ *ppTokenizer = 0;
+ *ppUserData = 0;
+ rc = SQLITE_ERROR;
+ }
+
+ return rc;
+}
+
/*
** Find a tokenizer. This is the implementation of the
** fts5_api.xFindTokenizer() method.
@@ -2801,53 +3460,75 @@ static int fts5FindTokenizer(
pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName);
if( pMod ){
- *pTokenizer = pMod->x;
- *ppUserData = pMod->pUserData;
+ if( pMod->bV2Native==0 ){
+ *ppUserData = pMod->pUserData;
+ }else{
+ *ppUserData = (void*)pMod;
+ }
+ *pTokenizer = pMod->x1;
}else{
- memset(pTokenizer, 0, sizeof(fts5_tokenizer));
+ memset(pTokenizer, 0, sizeof(*pTokenizer));
+ *ppUserData = 0;
rc = SQLITE_ERROR;
}
return rc;
}
-int sqlite3Fts5GetTokenizer(
- Fts5Global *pGlobal,
- const char **azArg,
- int nArg,
- Fts5Config *pConfig,
- char **pzErr
-){
- Fts5TokenizerModule *pMod;
+/*
+** Attempt to instantiate the tokenizer.
+*/
+int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
+ const char **azArg = pConfig->t.azArg;
+ const int nArg = pConfig->t.nArg;
+ Fts5TokenizerModule *pMod = 0;
int rc = SQLITE_OK;
- pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]);
+ pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]);
if( pMod==0 ){
assert( nArg>0 );
rc = SQLITE_ERROR;
- *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
+ sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]);
}else{
- rc = pMod->x.xCreate(
- pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0;
+ if( pMod->bV2Native ){
+ xCreate = pMod->x2.xCreate;
+ pConfig->t.pApi2 = &pMod->x2;
+ }else{
+ pConfig->t.pApi1 = &pMod->x1;
+ xCreate = pMod->x1.xCreate;
+ }
+
+ rc = xCreate(pMod->pUserData,
+ (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
);
- pConfig->pTokApi = &pMod->x;
+
if( rc!=SQLITE_OK ){
- if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
- }else{
- pConfig->ePattern = sqlite3Fts5TokenizerPattern(
- pMod->x.xCreate, pConfig->pTok
+ if( rc!=SQLITE_NOMEM ){
+ sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor");
+ }
+ }else if( pMod->bV2Native==0 ){
+ pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
+ pMod->x1.xCreate, pConfig->t.pTok
);
}
}
if( rc!=SQLITE_OK ){
- pConfig->pTokApi = 0;
- pConfig->pTok = 0;
+ pConfig->t.pApi1 = 0;
+ pConfig->t.pApi2 = 0;
+ pConfig->t.pTok = 0;
}
return rc;
}
+
+/*
+** xDestroy callback passed to sqlite3_create_module(). This is invoked
+** when the db handle is being closed. Free memory associated with
+** tokenizers and aux functions registered with this db handle.
+*/
static void fts5ModuleDestroy(void *pCtx){
Fts5TokenizerModule *pTok, *pNextTok;
Fts5Auxiliary *pAux, *pNextAux;
@@ -2868,6 +3549,10 @@ static void fts5ModuleDestroy(void *pCtx){
sqlite3_free(pGlobal);
}
+/*
+** Implementation of the fts5() function used by clients to obtain the
+** API pointer.
+*/
static void fts5Fts5Func(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
@@ -2894,6 +3579,81 @@ static void fts5SourceIdFunc(
sqlite3_result_text(pCtx, "--FTS5-SOURCE-ID--", -1, SQLITE_TRANSIENT);
}
+/*
+** Implementation of fts5_locale(LOCALE, TEXT) function.
+**
+** If parameter LOCALE is NULL, or a zero-length string, then a copy of
+** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
+** text, and the value returned is a blob consisting of:
+**
+** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER).
+** * The LOCALE, as utf-8 text, followed by
+** * 0x00, followed by
+** * The TEXT, as utf-8 text.
+**
+** There is no final nul-terminator following the TEXT value.
+*/
+static void fts5LocaleFunc(
+ sqlite3_context *pCtx, /* Function call context */
+ int nArg, /* Number of args */
+ sqlite3_value **apArg /* Function arguments */
+){
+ const char *zLocale = 0;
+ int nLocale = 0;
+ const char *zText = 0;
+ int nText = 0;
+
+ assert( nArg==2 );
+ UNUSED_PARAM(nArg);
+
+ zLocale = (const char*)sqlite3_value_text(apArg[0]);
+ nLocale = sqlite3_value_bytes(apArg[0]);
+
+ zText = (const char*)sqlite3_value_text(apArg[1]);
+ nText = sqlite3_value_bytes(apArg[1]);
+
+ if( zLocale==0 || zLocale[0]=='\0' ){
+ sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT);
+ }else{
+ Fts5Global *p = (Fts5Global*)sqlite3_user_data(pCtx);
+ u8 *pBlob = 0;
+ u8 *pCsr = 0;
+ int nBlob = 0;
+
+ nBlob = FTS5_LOCALE_HDR_SIZE + nLocale + 1 + nText;
+ pBlob = (u8*)sqlite3_malloc(nBlob);
+ if( pBlob==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ return;
+ }
+
+ pCsr = pBlob;
+ memcpy(pCsr, (const u8*)p->aLocaleHdr, FTS5_LOCALE_HDR_SIZE);
+ pCsr += FTS5_LOCALE_HDR_SIZE;
+ memcpy(pCsr, zLocale, nLocale);
+ pCsr += nLocale;
+ (*pCsr++) = 0x00;
+ if( zText ) memcpy(pCsr, zText, nText);
+ assert( &pCsr[nText]==&pBlob[nBlob] );
+
+ sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free);
+ }
+}
+
+/*
+** Implementation of fts5_insttoken() function.
+*/
+static void fts5InsttokenFunc(
+ sqlite3_context *pCtx, /* Function call context */
+ int nArg, /* Number of args */
+ sqlite3_value **apArg /* Function arguments */
+){
+ assert( nArg==1 );
+ (void)nArg;
+ sqlite3_result_value(pCtx, apArg[0]);
+ sqlite3_result_subtype(pCtx, FTS5_INSTTOKEN_SUBTYPE);
+}
+
/*
** Return true if zName is the extension on one of the shadow tables used
** by this module.
@@ -2914,7 +3674,7 @@ static int fts5ShadowName(const char *zName){
** if anything is found amiss. Return a NULL pointer if everything is
** OK.
*/
-static int fts5Integrity(
+static int fts5IntegrityMethod(
sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
const char *zSchema, /* Name of schema in which this table lives */
const char *zTabname, /* Name of the table itself */
@@ -2922,28 +3682,29 @@ static int fts5Integrity(
char **pzErr /* Write error message here */
){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- Fts5Config *pConfig = pTab->p.pConfig;
- char *zSql;
- char *zErr = 0;
int rc;
+
assert( pzErr!=0 && *pzErr==0 );
UNUSED_PARAM(isQuick);
- zSql = sqlite3_mprintf(
- "INSERT INTO \"%w\".\"%w\"(\"%w\") VALUES('integrity-check');",
- zSchema, zTabname, pConfig->zName);
- if( zSql==0 ) return SQLITE_NOMEM;
- rc = sqlite3_exec(pConfig->db, zSql, 0, 0, &zErr);
- sqlite3_free(zSql);
- if( (rc&0xff)==SQLITE_CORRUPT ){
- *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
- zSchema, zTabname);
- }else if( rc!=SQLITE_OK ){
- *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
- " FTS5 table %s.%s: %s",
- zSchema, zTabname, zErr);
+ assert( pTab->p.pConfig->pzErrmsg==0 );
+ pTab->p.pConfig->pzErrmsg = pzErr;
+ rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
+ if( *pzErr==0 && rc!=SQLITE_OK ){
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
+ zSchema, zTabname);
+ rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
+ }else{
+ *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS5 table %s.%s: %s",
+ zSchema, zTabname, sqlite3_errstr(rc));
+ }
}
- sqlite3_free(zErr);
- return SQLITE_OK;
+
+ sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
+ pTab->p.pConfig->pzErrmsg = 0;
+
+ return rc;
}
static int fts5Init(sqlite3 *db){
@@ -2972,7 +3733,7 @@ static int fts5Init(sqlite3 *db){
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
/* xShadowName */ fts5ShadowName,
- /* xIntegrity */ fts5Integrity
+ /* xIntegrity */ fts5IntegrityMethod
};
int rc;
@@ -2985,10 +3746,22 @@ static int fts5Init(sqlite3 *db){
void *p = (void*)pGlobal;
memset(pGlobal, 0, sizeof(Fts5Global));
pGlobal->db = db;
- pGlobal->api.iVersion = 2;
+ pGlobal->api.iVersion = 3;
pGlobal->api.xCreateFunction = fts5CreateAux;
pGlobal->api.xCreateTokenizer = fts5CreateTokenizer;
pGlobal->api.xFindTokenizer = fts5FindTokenizer;
+ pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2;
+ pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2;
+
+ /* Initialize pGlobal->aLocaleHdr[] to a 128-bit pseudo-random vector.
+ ** The constants below were generated randomly. */
+ sqlite3_randomness(sizeof(pGlobal->aLocaleHdr), pGlobal->aLocaleHdr);
+ pGlobal->aLocaleHdr[0] ^= 0xF924976D;
+ pGlobal->aLocaleHdr[1] ^= 0x16596E13;
+ pGlobal->aLocaleHdr[2] ^= 0x7C80BEAA;
+ pGlobal->aLocaleHdr[3] ^= 0x9B03A67F;
+ assert( sizeof(pGlobal->aLocaleHdr)==16 );
+
rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy);
if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db);
if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db);
@@ -3007,6 +3780,20 @@ static int fts5Init(sqlite3 *db){
p, fts5SourceIdFunc, 0, 0
);
}
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ db, "fts5_locale", 2,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE|SQLITE_SUBTYPE,
+ p, fts5LocaleFunc, 0, 0
+ );
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(
+ db, "fts5_insttoken", 1,
+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE,
+ p, fts5InsttokenFunc, 0, 0
+ );
+ }
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index 9480da7c52..2b43016bef 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -16,13 +16,40 @@
#include "fts5Int.h"
+/*
+** pSavedRow:
+** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it
+** does a by-rowid lookup to retrieve a single row from the %_content
+** table or equivalent external-content table/view.
+**
+** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original
+** values for a row being UPDATEd. In that case, the SQL statement is
+** not reset and pSavedRow is set to point at it. This is so that the
+** insert operation that follows the delete may access the original
+** row values for any new values for which sqlite3_value_nochange() returns
+** true. i.e. if the user executes:
+**
+** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1);
+** ...
+** UPDATE fts SET a=?, b=? WHERE rowid=?;
+**
+** then the value passed to the xUpdate() method of this table as the
+** new.c value is an sqlite3_value_nochange() value. So in this case it
+** must be read from the saved row stored in Fts5Storage.pSavedRow.
+**
+** This is necessary - using sqlite3_value_nochange() instead of just having
+** SQLite pass the original value back via xUpdate() - so as not to discard
+** any locale information associated with such values.
+**
+*/
struct Fts5Storage {
Fts5Config *pConfig;
Fts5Index *pIndex;
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
i64 nTotalRow; /* Total number of rows in FTS table */
i64 *aTotalSize; /* Total sizes of each column */
- sqlite3_stmt *aStmt[11];
+ sqlite3_stmt *pSavedRow;
+ sqlite3_stmt *aStmt[12];
};
@@ -36,14 +63,15 @@ struct Fts5Storage {
# error "FTS5_STMT_LOOKUP mismatch"
#endif
-#define FTS5_STMT_INSERT_CONTENT 3
-#define FTS5_STMT_REPLACE_CONTENT 4
-#define FTS5_STMT_DELETE_CONTENT 5
-#define FTS5_STMT_REPLACE_DOCSIZE 6
-#define FTS5_STMT_DELETE_DOCSIZE 7
-#define FTS5_STMT_LOOKUP_DOCSIZE 8
-#define FTS5_STMT_REPLACE_CONFIG 9
-#define FTS5_STMT_SCAN 10
+#define FTS5_STMT_LOOKUP2 3
+#define FTS5_STMT_INSERT_CONTENT 4
+#define FTS5_STMT_REPLACE_CONTENT 5
+#define FTS5_STMT_DELETE_CONTENT 6
+#define FTS5_STMT_REPLACE_DOCSIZE 7
+#define FTS5_STMT_DELETE_DOCSIZE 8
+#define FTS5_STMT_LOOKUP_DOCSIZE 9
+#define FTS5_STMT_REPLACE_CONFIG 10
+#define FTS5_STMT_SCAN 11
/*
** Prepare the two insert statements - Fts5Storage.pInsertContent and
@@ -73,6 +101,7 @@ static int fts5StorageGetStmt(
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
+ "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
@@ -88,6 +117,8 @@ static int fts5StorageGetStmt(
Fts5Config *pC = p->pConfig;
char *zSql = 0;
+ assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
+
switch( eStmt ){
case FTS5_STMT_SCAN:
zSql = sqlite3_mprintf(azStmt[eStmt],
@@ -104,6 +135,7 @@ static int fts5StorageGetStmt(
break;
case FTS5_STMT_LOOKUP:
+ case FTS5_STMT_LOOKUP2:
zSql = sqlite3_mprintf(azStmt[eStmt],
pC->zContentExprlist, pC->zContent, pC->zContentRowid
);
@@ -111,20 +143,35 @@ static int fts5StorageGetStmt(
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
- int nCol = pC->nCol + 1;
- char *zBind;
+ char *zBind = 0;
int i;
- zBind = sqlite3_malloc64(1 + nCol*2);
- if( zBind ){
- for(i=0; ieContent==FTS5_CONTENT_NORMAL
+ || pC->eContent==FTS5_CONTENT_UNINDEXED
+ );
+
+ /* Add bindings for the "c*" columns - those that store the actual
+ ** table content. If eContent==NORMAL, then there is one binding
+ ** for each column. Or, if eContent==UNINDEXED, then there are only
+ ** bindings for the UNINDEXED columns. */
+ for(i=0; rc==SQLITE_OK && i<(pC->nCol+1); i++){
+ if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
+ zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
}
- zBind[i*2-1] = '\0';
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
- sqlite3_free(zBind);
}
+
+ /* Add bindings for any "l*" columns. Only non-UNINDEXED columns
+ ** require these. */
+ if( pC->bLocale && pC->eContent==FTS5_CONTENT_NORMAL ){
+ for(i=0; rc==SQLITE_OK && inCol; i++){
+ if( pC->abUnindexed[i]==0 ){
+ zBind = sqlite3Fts5Mprintf(&rc, "%z,?%d", zBind, pC->nCol+i+2);
+ }
+ }
+ }
+
+ zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
+ sqlite3_free(zBind);
break;
}
@@ -150,7 +197,7 @@ static int fts5StorageGetStmt(
rc = SQLITE_NOMEM;
}else{
int f = SQLITE_PREPARE_PERSISTENT;
- if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
+ if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
p->pConfig->bLock++;
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
p->pConfig->bLock--;
@@ -158,6 +205,11 @@ static int fts5StorageGetStmt(
if( rc!=SQLITE_OK && pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
}
+ if( rc==SQLITE_ERROR && eStmt>FTS5_STMT_LOOKUP2 && eStmtpIndex = pIndex;
if( bCreate ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
int nDefn = 32 + pConfig->nCol*10;
- char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
+ char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20);
if( zDefn==0 ){
rc = SQLITE_NOMEM;
}else{
@@ -321,8 +375,20 @@ int sqlite3Fts5StorageOpen(
sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
iOff = (int)strlen(zDefn);
for(i=0; inCol; i++){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->abUnindexed[i]
+ ){
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
+ if( pConfig->bLocale ){
+ for(i=0; inCol; i++){
+ if( pConfig->abUnindexed[i]==0 ){
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
+ }
}
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
}
@@ -399,15 +465,49 @@ static int fts5StorageInsertCallback(
return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
}
+/*
+** This function is used as part of an UPDATE statement that modifies the
+** rowid of a row. In that case, this function is called first to set
+** Fts5Storage.pSavedRow to point to a statement that may be used to
+** access the original values of the row being deleted - iDel.
+**
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
+** It is not considered an error if row iDel does not exist. In this case
+** pSavedRow is not set and SQLITE_OK returned.
+*/
+int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
+ int rc = SQLITE_OK;
+ sqlite3_stmt *pSeek = 0;
+
+ assert( p->pSavedRow==0 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pSeek, 1, iDel);
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
+ rc = sqlite3_reset(pSeek);
+ }else{
+ p->pSavedRow = pSeek;
+ }
+ }
+
+ return rc;
+}
+
/*
** If a row with rowid iDel is present in the %_content table, add the
** delete-markers to the FTS index necessary to delete it. Do not actually
** remove the %_content row at this time though.
+**
+** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left
+** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access
+** the original values of the row being deleted. This is used by UPDATE
+** statements.
*/
static int fts5StorageDeleteFromIndex(
Fts5Storage *p,
i64 iDel,
- sqlite3_value **apVal
+ sqlite3_value **apVal,
+ int bSaveRow /* True to set pSavedRow */
){
Fts5Config *pConfig = p->pConfig;
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
@@ -416,12 +516,21 @@ static int fts5StorageDeleteFromIndex(
int iCol;
Fts5InsertCtx ctx;
+ assert( bSaveRow==0 || apVal==0 );
+ assert( bSaveRow==0 || bSaveRow==1 );
+ assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
+
if( apVal==0 ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
- if( rc!=SQLITE_OK ) return rc;
- sqlite3_bind_int64(pSeek, 1, iDel);
- if( sqlite3_step(pSeek)!=SQLITE_ROW ){
- return sqlite3_reset(pSeek);
+ if( p->pSavedRow && bSaveRow ){
+ pSeek = p->pSavedRow;
+ p->pSavedRow = 0;
+ }else{
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
+ if( rc!=SQLITE_OK ) return rc;
+ sqlite3_bind_int64(pSeek, 1, iDel);
+ if( sqlite3_step(pSeek)!=SQLITE_ROW ){
+ return sqlite3_reset(pSeek);
+ }
}
}
@@ -429,26 +538,42 @@ static int fts5StorageDeleteFromIndex(
ctx.iCol = -1;
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
- const char *zText;
- int nText;
+ sqlite3_value *pVal = 0;
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+
assert( pSeek==0 || apVal==0 );
assert( pSeek!=0 || apVal!=0 );
if( pSeek ){
- zText = (const char*)sqlite3_column_text(pSeek, iCol);
- nText = sqlite3_column_bytes(pSeek, iCol);
- }else if( ALWAYS(apVal) ){
- zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
- nText = sqlite3_value_bytes(apVal[iCol-1]);
+ pVal = sqlite3_column_value(pSeek, iCol);
}else{
- continue;
+ pVal = apVal[iCol-1];
}
- ctx.szCol = 0;
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
- zText, nText, (void*)&ctx, fts5StorageInsertCallback
- );
- p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
- if( p->aTotalSize[iCol-1]<0 ){
- rc = FTS5_CORRUPT;
+
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale && pSeek ){
+ pLoc = (const char*)sqlite3_column_text(pSeek, iCol + pConfig->nCol);
+ nLoc = sqlite3_column_bytes(pSeek, iCol + pConfig->nCol);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ ctx.szCol = 0;
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
+ pText, nText, (void*)&ctx, fts5StorageInsertCallback
+ );
+ p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
+ if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){
+ rc = FTS5_CORRUPT;
+ }
+ sqlite3Fts5ClearLocale(pConfig);
}
}
}
@@ -458,11 +583,29 @@ static int fts5StorageDeleteFromIndex(
p->nTotalRow--;
}
- rc2 = sqlite3_reset(pSeek);
- if( rc==SQLITE_OK ) rc = rc2;
+ if( rc==SQLITE_OK && bSaveRow ){
+ assert( p->pSavedRow==0 );
+ p->pSavedRow = pSeek;
+ }else{
+ rc2 = sqlite3_reset(pSeek);
+ if( rc==SQLITE_OK ) rc = rc2;
+ }
return rc;
}
+/*
+** Reset any saved statement pSavedRow. Zero pSavedRow as well. This
+** should be called by the xUpdate() method of the fts5 table before
+** returning from any operation that may have set Fts5Storage.pSavedRow.
+*/
+void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
+ assert( pStorage->pSavedRow==0
+ || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2]
+ );
+ sqlite3_reset(pStorage->pSavedRow);
+ pStorage->pSavedRow = 0;
+}
+
/*
** This function is called to process a DELETE on a contentless_delete=1
** table. It adds the tombstone required to delete the entry with rowid
@@ -475,7 +618,9 @@ static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
int rc = SQLITE_OK;
assert( p->pConfig->bContentlessDelete );
- assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE
+ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ );
/* Look up the origin of the document in the %_docsize table. Store
** this in stack variable iOrigin. */
@@ -519,12 +664,12 @@ static int fts5StorageInsertDocsize(
rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
sqlite3_bind_int64(pReplace, 3, iOrigin);
}
- if( rc==SQLITE_OK ){
- sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- sqlite3_bind_null(pReplace, 2);
- }
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
+ sqlite3_step(pReplace);
+ rc = sqlite3_reset(pReplace);
+ sqlite3_bind_null(pReplace, 2);
}
}
return rc;
@@ -578,7 +723,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
/*
** Remove a row from the FTS table.
*/
-int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
+int sqlite3Fts5StorageDelete(
+ Fts5Storage *p, /* Storage object */
+ i64 iDel, /* Rowid to delete from table */
+ sqlite3_value **apVal, /* Optional - values to remove from index */
+ int bSaveRow /* If true, set pSavedRow for deleted row */
+){
Fts5Config *pConfig = p->pConfig;
int rc;
sqlite3_stmt *pDel = 0;
@@ -594,8 +744,14 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
if( rc==SQLITE_OK ){
if( p->pConfig->bContentlessDelete ){
rc = fts5StorageContentlessDelete(p, iDel);
+ if( rc==SQLITE_OK
+ && bSaveRow
+ && p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
+ rc = sqlite3Fts5StorageFindDeleteRow(p, iDel);
+ }
}else{
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
}
}
@@ -610,7 +766,9 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
}
/* Delete the %_content record */
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
}
@@ -642,8 +800,13 @@ int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
);
if( rc==SQLITE_OK && pConfig->bColumnsize ){
rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
+ "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
+ );
+ }
+
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
+ rc = fts5ExecPrintf(pConfig->db, 0,
+ "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
);
}
@@ -673,7 +836,7 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
@@ -684,14 +847,36 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
- int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pLoc in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ if( pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
+ nLoc = sqlite3_column_bytes(pScan, iCol);
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -757,6 +942,7 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
*/
int sqlite3Fts5StorageContentInsert(
Fts5Storage *p,
+ int bReplace, /* True to use REPLACE instead of INSERT */
sqlite3_value **apVal,
i64 *piRowid
){
@@ -764,7 +950,9 @@ int sqlite3Fts5StorageContentInsert(
int rc = SQLITE_OK;
/* Insert the new row into the %_content table. */
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
+ && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
+ ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
@@ -773,9 +961,52 @@ int sqlite3Fts5StorageContentInsert(
}else{
sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
int i; /* Counter variable */
- rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
- for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
- rc = sqlite3_bind_value(pInsert, i, apVal[i]);
+
+ assert( FTS5_STMT_INSERT_CONTENT+1==FTS5_STMT_REPLACE_CONTENT );
+ assert( bReplace==0 || bReplace==1 );
+ rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT+bReplace, &pInsert, 0);
+ if( pInsert ) sqlite3_clear_bindings(pInsert);
+
+ /* Bind the rowid value */
+ sqlite3_bind_value(pInsert, 1, apVal[1]);
+
+ /* Loop through values for user-defined columns. i=2 is the leftmost
+ ** user-defined column. As is column 1 of pSavedRow. */
+ for(i=2; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
+ int bUnindexed = pConfig->abUnindexed[i-2];
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || bUnindexed ){
+ sqlite3_value *pVal = apVal[i];
+
+ if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
+ /* This is an UPDATE statement, and user-defined column (i-2) was not
+ ** modified. Retrieve the value from Fts5Storage.pSavedRow. */
+ pVal = sqlite3_column_value(p->pSavedRow, i-1);
+ if( pConfig->bLocale && bUnindexed==0 ){
+ sqlite3_bind_value(pInsert, pConfig->nCol + i,
+ sqlite3_column_value(p->pSavedRow, pConfig->nCol + i - 1)
+ );
+ }
+ }else if( sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ const char *pText = 0;
+ const char *pLoc = 0;
+ int nText = 0;
+ int nLoc = 0;
+ assert( pConfig->bLocale );
+
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
+ if( bUnindexed==0 ){
+ int iLoc = pConfig->nCol + i;
+ sqlite3_bind_text(pInsert, iLoc, pLoc, nLoc, SQLITE_TRANSIENT);
+ }
+ }
+
+ continue;
+ }
+
+ rc = sqlite3_bind_value(pInsert, i, pVal);
+ }
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
@@ -810,14 +1041,38 @@ int sqlite3Fts5StorageIndexInsert(
for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){
ctx.szCol = 0;
if( pConfig->abUnindexed[ctx.iCol]==0 ){
- const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
- int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageInsertCallback
- );
+ int nText = 0; /* Size of pText in bytes */
+ const char *pText = 0; /* Pointer to buffer containing text value */
+ int nLoc = 0; /* Size of pText in bytes */
+ const char *pLoc = 0; /* Pointer to buffer containing text value */
+
+ sqlite3_value *pVal = apVal[ctx.iCol+2];
+ if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
+ pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = ctx.iCol + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(p->pSavedRow, iCol);
+ nLoc = sqlite3_column_bytes(p->pSavedRow, iCol);
+ }
+ }else{
+ pVal = apVal[ctx.iCol+2];
+ }
+
+ if( pConfig->bLocale && sqlite3Fts5IsLocaleValue(pConfig, pVal) ){
+ rc = sqlite3Fts5DecodeLocaleValue(pVal, &pText, &nText, &pLoc, &nLoc);
+ }else{
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx,
+ fts5StorageInsertCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
}
sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
@@ -981,29 +1236,61 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
}
for(i=0; rc==SQLITE_OK && inCol; i++){
- if( pConfig->abUnindexed[i] ) continue;
- ctx.iCol = i;
- ctx.szCol = 0;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
- }
- if( rc==SQLITE_OK ){
- const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
- int nText = sqlite3_column_bytes(pScan, i+1);
- rc = sqlite3Fts5Tokenize(pConfig,
- FTS5_TOKENIZE_DOCUMENT,
- zText, nText,
- (void*)&ctx,
- fts5StorageIntegrityCallback
- );
- }
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
- rc = FTS5_CORRUPT;
- }
- aTotalSize[i] += ctx.szCol;
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
- sqlite3Fts5TermsetFree(ctx.pTermset);
- ctx.pTermset = 0;
+ if( pConfig->abUnindexed[i]==0 ){
+ const char *pText = 0;
+ int nText = 0;
+ const char *pLoc = 0;
+ int nLoc = 0;
+ sqlite3_value *pVal = sqlite3_column_value(pScan, i+1);
+
+ if( pConfig->eContent==FTS5_CONTENT_EXTERNAL
+ && sqlite3Fts5IsLocaleValue(pConfig, pVal)
+ ){
+ rc = sqlite3Fts5DecodeLocaleValue(
+ pVal, &pText, &nText, &pLoc, &nLoc
+ );
+ }else{
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL && pConfig->bLocale ){
+ int iCol = i + 1 + pConfig->nCol;
+ pLoc = (const char*)sqlite3_column_text(pScan, iCol);
+ nLoc = sqlite3_column_bytes(pScan, iCol);
+ }
+ pText = (const char*)sqlite3_value_text(pVal);
+ nText = sqlite3_value_bytes(pVal);
+ }
+
+ ctx.iCol = i;
+ ctx.szCol = 0;
+
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
+ }
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts5SetLocale(pConfig, pLoc, nLoc);
+ rc = sqlite3Fts5Tokenize(pConfig,
+ FTS5_TOKENIZE_DOCUMENT,
+ pText, nText,
+ (void*)&ctx,
+ fts5StorageIntegrityCallback
+ );
+ sqlite3Fts5ClearLocale(pConfig);
+ }
+
+ /* If this is not a columnsize=0 database, check that the number
+ ** of tokens in the value matches the aColSize[] value read from
+ ** the %_docsize table. */
+ if( rc==SQLITE_OK
+ && pConfig->bColumnsize
+ && ctx.szCol!=aColSize[i]
+ ){
+ rc = FTS5_CORRUPT;
+ }
+ aTotalSize[i] += ctx.szCol;
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
+ sqlite3Fts5TermsetFree(ctx.pTermset);
+ ctx.pTermset = 0;
+ }
}
}
sqlite3Fts5TermsetFree(ctx.pTermset);
diff --git a/ext/fts5/fts5_tcl.c b/ext/fts5/fts5_tcl.c
index 80c600dbb1..25cd5c0633 100644
--- a/ext/fts5/fts5_tcl.c
+++ b/ext/fts5/fts5_tcl.c
@@ -14,20 +14,14 @@
#ifdef SQLITE_TEST
-#if defined(INCLUDE_SQLITE_TCL_H)
-# include "sqlite_tcl.h"
-#else
-# include "tcl.h"
-# ifndef SQLITE_TCLAPI
-# define SQLITE_TCLAPI
-# endif
-#endif
+#include "tclsqlite.h"
#ifdef SQLITE_ENABLE_FTS5
#include "fts5.h"
#include
#include
+#include
#ifdef SQLITE_DEBUG
extern int sqlite3_fts5_may_be_corrupt;
@@ -103,14 +97,14 @@ static int SQLITE_TCLAPI f5tDbAndApi(
rc = sqlite3_prepare_v2(db, "SELECT fts5(?1)", -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr", 0);
sqlite3_step(pStmt);
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
@@ -244,6 +238,10 @@ static int SQLITE_TCLAPI xF5tApi(
{ "xGetAuxdataInt", 1, "CLEAR" }, /* 15 */
{ "xPhraseForeach", 4, "IPHRASE COLVAR OFFVAR SCRIPT" }, /* 16 */
{ "xPhraseColumnForeach", 3, "IPHRASE COLVAR SCRIPT" }, /* 17 */
+
+ { "xQueryToken", 2, "IPHRASE ITERM" }, /* 18 */
+ { "xInstToken", 2, "IDX ITERM" }, /* 19 */
+ { "xColumnLocale", 1, "COL" }, /* 20 */
{ 0, 0, 0}
};
@@ -294,12 +292,12 @@ static int SQLITE_TCLAPI xF5tApi(
break;
}
CASE(3, "xTokenize") {
- int nText;
+ Tcl_Size nText;
char *zText = Tcl_GetStringFromObj(objv[2], &nText);
F5tFunction ctx;
ctx.interp = interp;
ctx.pScript = objv[3];
- rc = p->pApi->xTokenize(p->pFts, zText, nText, &ctx, xTokenizeCb);
+ rc = p->pApi->xTokenize(p->pFts, zText, (int)nText, &ctx, xTokenizeCb);
if( rc==SQLITE_OK ){
Tcl_ResetResult(interp);
}
@@ -395,7 +393,7 @@ static int SQLITE_TCLAPI xF5tApi(
CASE(12, "xSetAuxdata") {
F5tAuxData *pData = (F5tAuxData*)sqlite3_malloc(sizeof(F5tAuxData));
if( pData==0 ){
- Tcl_AppendResult(interp, "out of memory", 0);
+ Tcl_AppendResult(interp, "out of memory", (char*)0);
return TCL_ERROR;
}
pData->pObj = objv[2];
@@ -455,7 +453,7 @@ static int SQLITE_TCLAPI xF5tApi(
rc = p->pApi->xPhraseFirst(p->pFts, iPhrase, &iter, &iCol, &iOff);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), (char*)0);
return TCL_ERROR;
}
for( ;iCol>=0; p->pApi->xPhraseNext(p->pFts, &iter, &iCol, &iOff) ){
@@ -500,6 +498,52 @@ static int SQLITE_TCLAPI xF5tApi(
break;
}
+ CASE(18, "xQueryToken") {
+ const char *pTerm = 0;
+ int nTerm = 0;
+ int iPhrase = 0;
+ int iTerm = 0;
+
+ if( Tcl_GetIntFromObj(interp, objv[2], &iPhrase) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
+ rc = p->pApi->xQueryToken(p->pFts, iPhrase, iTerm, &pTerm, &nTerm);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
+ }
+
+ break;
+ }
+
+ CASE(19, "xInstToken") {
+ const char *pTerm = 0;
+ int nTerm = 0;
+ int iIdx = 0;
+ int iTerm = 0;
+
+ if( Tcl_GetIntFromObj(interp, objv[2], &iIdx) ) return TCL_ERROR;
+ if( Tcl_GetIntFromObj(interp, objv[3], &iTerm) ) return TCL_ERROR;
+ rc = p->pApi->xInstToken(p->pFts, iIdx, iTerm, &pTerm, &nTerm);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(pTerm, nTerm));
+ }
+
+ break;
+ }
+
+ CASE(20, "xColumnLocale") {
+ const char *z = 0;
+ int n = 0;
+ int iCol;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){
+ return TCL_ERROR;
+ }
+ rc = p->pApi->xColumnLocale(p->pFts, iCol, &z, &n);
+ if( rc==SQLITE_OK && z ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(z, n));
+ }
+ break;
+ }
+
default:
assert( 0 );
break;
@@ -570,15 +614,16 @@ static void xF5tFunction(
sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
- int n;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */
- unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n);
- sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT);
+ Tcl_Size nn;
+ unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &nn);
+ sqlite3_result_blob(pCtx, data, (int)nn, SQLITE_TRANSIENT);
}else if( c=='b' && strcmp(zType,"boolean")==0 ){
+ int n;
Tcl_GetIntFromObj(0, pVar, &n);
sqlite3_result_int(pCtx, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -591,8 +636,9 @@ static void xF5tFunction(
Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(pCtx, v);
}else{
- unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
- sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT);
+ Tcl_Size nn;
+ unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &nn);
+ sqlite3_result_text(pCtx, (char*)data, (int)nn, SQLITE_TRANSIENT);
}
}
}
@@ -638,7 +684,7 @@ static int SQLITE_TCLAPI f5tCreateFunction(
pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy
);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (char*)0);
return TCL_ERROR;
}
@@ -684,8 +730,9 @@ static int SQLITE_TCLAPI f5tTokenize(
int objc,
Tcl_Obj *CONST objv[]
){
- char *zText;
- int nText;
+ char *pCopy = 0;
+ char *zText = 0;
+ Tcl_Size nText = 0;
sqlite3 *db = 0;
fts5_api *pApi = 0;
Fts5Tokenizer *pTok = 0;
@@ -694,7 +741,7 @@ static int SQLITE_TCLAPI f5tTokenize(
void *pUserdata;
int rc;
- int nArg;
+ Tcl_Size nArg;
const char **azArg;
F5tTokenizeCtx ctx;
@@ -705,7 +752,7 @@ static int SQLITE_TCLAPI f5tTokenize(
if( objc==5 ){
char *zOpt = Tcl_GetString(objv[1]);
if( strcmp("-subst", zOpt) ){
- Tcl_AppendResult(interp, "unrecognized option: ", zOpt, 0);
+ Tcl_AppendResult(interp, "unrecognized option: ", zOpt, (char*)0);
return TCL_ERROR;
}
}
@@ -714,7 +761,7 @@ static int SQLITE_TCLAPI f5tTokenize(
return TCL_ERROR;
}
if( nArg==0 ){
- Tcl_AppendResult(interp, "no such tokenizer: ", 0);
+ Tcl_AppendResult(interp, "no such tokenizer: ", (char*)0);
Tcl_Free((void*)azArg);
return TCL_ERROR;
}
@@ -722,32 +769,43 @@ static int SQLITE_TCLAPI f5tTokenize(
rc = pApi->xFindTokenizer(pApi, azArg[0], &pUserdata, &tokenizer);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], 0);
+ Tcl_AppendResult(interp, "no such tokenizer: ", azArg[0], (char*)0);
return TCL_ERROR;
}
- rc = tokenizer.xCreate(pUserdata, &azArg[1], nArg-1, &pTok);
+ rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
+ Tcl_AppendResult(interp, "error in tokenizer.xCreate()", (char*)0);
return TCL_ERROR;
}
+ if( nText>0 ){
+ pCopy = sqlite3_malloc(nText);
+ if( pCopy==0 ){
+ tokenizer.xDelete(pTok);
+ Tcl_AppendResult(interp, "error in sqlite3_malloc()", (char*)0);
+ return TCL_ERROR;
+ }else{
+ memcpy(pCopy, zText, nText);
+ }
+ }
+
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
ctx.bSubst = (objc==5);
ctx.pRet = pRet;
- ctx.zInput = zText;
+ ctx.zInput = pCopy;
rc = tokenizer.xTokenize(
- pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText, nText, xTokenizeCb2
+ pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, pCopy,(int)nText, xTokenizeCb2
);
tokenizer.xDelete(pTok);
+ sqlite3_free(pCopy);
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", 0);
+ Tcl_AppendResult(interp, "error in tokenizer.xTokenize()", (char*)0);
Tcl_DecrRefCount(pRet);
return TCL_ERROR;
}
-
Tcl_Free((void*)azArg);
Tcl_SetObjResult(interp, pRet);
Tcl_DecrRefCount(pRet);
@@ -766,18 +824,32 @@ typedef struct F5tTokenizerInstance F5tTokenizerInstance;
struct F5tTokenizerContext {
void *pCtx;
int (*xToken)(void*, int, const char*, int, int, int);
+ F5tTokenizerInstance *pInst;
};
struct F5tTokenizerModule {
Tcl_Interp *interp;
Tcl_Obj *pScript;
+ void *pParentCtx;
+ fts5_tokenizer_v2 parent_v2;
+ fts5_tokenizer parent;
F5tTokenizerContext *pContext;
};
+/*
+** zLocale:
+** Within a call to xTokenize_v2(), pLocale/nLocale store the locale
+** passed to the call by fts5. This can be retrieved by a Tcl tokenize
+** script using [sqlite3_fts5_locale].
+*/
struct F5tTokenizerInstance {
Tcl_Interp *interp;
Tcl_Obj *pScript;
+ F5tTokenizerModule *pModule;
+ Fts5Tokenizer *pParent;
F5tTokenizerContext *pContext;
+ const char *pLocale;
+ int nLocale;
};
static int f5tTokenizerCreate(
@@ -786,11 +858,20 @@ static int f5tTokenizerCreate(
int nArg,
Fts5Tokenizer **ppOut
){
+ Fts5Tokenizer *pParent = 0;
F5tTokenizerModule *pMod = (F5tTokenizerModule*)pCtx;
Tcl_Obj *pEval;
int rc = TCL_OK;
int i;
+ assert( pMod->parent_v2.xCreate==0 || pMod->parent.xCreate==0 );
+ if( pMod->parent_v2.xCreate ){
+ rc = pMod->parent_v2.xCreate(pMod->pParentCtx, 0, 0, &pParent);
+ }
+ if( pMod->parent.xCreate ){
+ rc = pMod->parent.xCreate(pMod->pParentCtx, 0, 0, &pParent);
+ }
+
pEval = Tcl_DuplicateObj(pMod->pScript);
Tcl_IncrRefCount(pEval);
for(i=0; rc==TCL_OK && iinterp = pMod->interp;
pInst->pScript = Tcl_GetObjResult(pMod->interp);
pInst->pContext = pMod->pContext;
+ pInst->pParent = pParent;
+ pInst->pModule = pMod;
Tcl_IncrRefCount(pInst->pScript);
*ppOut = (Fts5Tokenizer*)pInst;
}
@@ -820,11 +903,21 @@ static int f5tTokenizerCreate(
static void f5tTokenizerDelete(Fts5Tokenizer *p){
F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
- Tcl_DecrRefCount(pInst->pScript);
- ckfree((char *)pInst);
+ if( pInst ){
+ if( pInst->pParent ){
+ if( pInst->pModule->parent_v2.xDelete ){
+ pInst->pModule->parent_v2.xDelete(pInst->pParent);
+ }else{
+ pInst->pModule->parent.xDelete(pInst->pParent);
+ }
+ }
+ Tcl_DecrRefCount(pInst->pScript);
+ ckfree((char *)pInst);
+ }
}
-static int f5tTokenizerTokenize(
+
+static int f5tTokenizerReallyTokenize(
Fts5Tokenizer *p,
void *pCtx,
int flags,
@@ -832,6 +925,7 @@ static int f5tTokenizerTokenize(
int (*xToken)(void*, int, const char*, int, int, int)
){
F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
+ F5tTokenizerInstance *pOldInst = 0;
void *pOldCtx;
int (*xOldToken)(void*, int, const char*, int, int, int);
Tcl_Obj *pEval;
@@ -840,9 +934,11 @@ static int f5tTokenizerTokenize(
pOldCtx = pInst->pContext->pCtx;
xOldToken = pInst->pContext->xToken;
+ pOldInst = pInst->pContext->pInst;
pInst->pContext->pCtx = pCtx;
pInst->pContext->xToken = xToken;
+ pInst->pContext->pInst = pInst;
assert(
flags==FTS5_TOKENIZE_DOCUMENT
@@ -878,9 +974,105 @@ static int f5tTokenizerTokenize(
pInst->pContext->pCtx = pOldCtx;
pInst->pContext->xToken = xOldToken;
+ pInst->pContext->pInst = pOldInst;
return rc;
}
+typedef struct CallbackCtx CallbackCtx;
+struct CallbackCtx {
+ Fts5Tokenizer *p;
+ void *pCtx;
+ int flags;
+ int (*xToken)(void*, int, const char*, int, int, int);
+};
+
+static int f5tTokenizeCallback(
+ void *pCtx,
+ int tflags,
+ const char *z, int n,
+ int iStart, int iEnd
+){
+ CallbackCtx *p = (CallbackCtx*)pCtx;
+ return f5tTokenizerReallyTokenize(p->p, p->pCtx, p->flags, z, n, p->xToken);
+}
+
+static int f5tTokenizerTokenize_v2(
+ Fts5Tokenizer *p,
+ void *pCtx,
+ int flags,
+ const char *pText, int nText,
+ const char *pLoc, int nLoc,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ int rc = SQLITE_OK;
+ F5tTokenizerInstance *pInst = (F5tTokenizerInstance*)p;
+
+ pInst->pLocale = pLoc;
+ pInst->nLocale = nLoc;
+
+ if( pInst->pParent ){
+ CallbackCtx ctx;
+ ctx.p = p;
+ ctx.pCtx = pCtx;
+ ctx.flags = flags;
+ ctx.xToken = xToken;
+ if( pInst->pModule->parent_v2.xTokenize ){
+ rc = pInst->pModule->parent_v2.xTokenize(
+ pInst->pParent, (void*)&ctx, flags, pText, nText,
+ pLoc, nLoc, f5tTokenizeCallback
+ );
+ }else{
+ rc = pInst->pModule->parent.xTokenize(
+ pInst->pParent, (void*)&ctx, flags, pText, nText, f5tTokenizeCallback
+ );
+ }
+ }else{
+ rc = f5tTokenizerReallyTokenize(p, pCtx, flags, pText, nText, xToken);
+ }
+
+ pInst->pLocale = 0;
+ pInst->nLocale = 0;
+ return rc;
+}
+static int f5tTokenizerTokenize(
+ Fts5Tokenizer *p,
+ void *pCtx,
+ int flags,
+ const char *pText, int nText,
+ int (*xToken)(void*, int, const char*, int, int, int)
+){
+ return f5tTokenizerTokenize_v2(p, pCtx, flags, pText, nText, 0, 0, xToken);
+}
+
+/*
+** sqlite3_fts5_locale
+*/
+static int SQLITE_TCLAPI f5tTokenizerLocale(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
+
+ if( objc!=1 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "");
+ return TCL_ERROR;
+ }
+
+ if( p->xToken==0 ){
+ Tcl_AppendResult(interp,
+ "sqlite3_fts5_locale may only be used by tokenizer callback", (char*)0
+ );
+ return TCL_ERROR;
+ }
+
+ Tcl_SetObjResult(interp,
+ Tcl_NewStringObj(p->pInst->pLocale, p->pInst->nLocale)
+ );
+ return TCL_OK;
+}
+
/*
** sqlite3_fts5_token ?-colocated? TEXT START END
*/
@@ -893,13 +1085,13 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
int iStart;
int iEnd;
- int nToken;
+ Tcl_Size nToken;
int tflags = 0;
char *zToken;
int rc;
if( objc==5 ){
- int nArg;
+ Tcl_Size nArg;
char *zArg = Tcl_GetStringFromObj(objv[1], &nArg);
if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){
tflags |= FTS5_TOKEN_COLOCATED;
@@ -919,12 +1111,12 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
if( p->xToken==0 ){
Tcl_AppendResult(interp,
- "sqlite3_fts5_token may only be used by tokenizer callback", 0
+ "sqlite3_fts5_token may only be used by tokenizer callback", (char*)0
);
return TCL_ERROR;
}
- rc = p->xToken(p->pCtx, tflags, zToken, nToken, iStart, iEnd);
+ rc = p->xToken(p->pCtx, tflags, zToken, (int)nToken, iStart, iEnd);
Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
return rc==SQLITE_OK ? TCL_OK : TCL_ERROR;
@@ -966,32 +1158,112 @@ static int SQLITE_TCLAPI f5tCreateTokenizer(
fts5_api *pApi;
char *zName;
Tcl_Obj *pScript;
- fts5_tokenizer t;
F5tTokenizerModule *pMod;
- int rc;
-
- if( objc!=4 ){
- Tcl_WrongNumArgs(interp, 1, objv, "DB NAME SCRIPT");
+ int rc = SQLITE_OK;
+ int bV2 = 0; /* True to use _v2 API */
+ int iVersion = 2; /* Value for _v2.iVersion */
+ const char *zParent = 0; /* Name of parent tokenizer, if any */
+ int ii = 0;
+
+ if( objc<4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "?OPTIONS? DB NAME SCRIPT");
return TCL_ERROR;
}
- if( f5tDbAndApi(interp, objv[1], &db, &pApi) ){
- return TCL_ERROR;
+
+ /* Parse any options. Set stack variables bV2 and zParent. */
+ for(ii=1; iiinterp = interp;
pMod->pScript = pScript;
- pMod->pContext = pContext;
Tcl_IncrRefCount(pScript);
- rc = pApi->xCreateTokenizer(pApi, zName, (void*)pMod, &t, f5tDelTokenizer);
+ pMod->pContext = pContext;
+ if( zParent ){
+ if( bV2 ){
+ fts5_tokenizer_v2 *pParent = 0;
+ rc = pApi->xFindTokenizer_v2(pApi, zParent, &pMod->pParentCtx, &pParent);
+ if( rc==SQLITE_OK ){
+ memcpy(&pMod->parent_v2, pParent, sizeof(fts5_tokenizer_v2));
+ pMod->parent_v2.xDelete(0);
+ }
+ }else{
+ rc = pApi->xFindTokenizer(pApi, zParent, &pMod->pParentCtx,&pMod->parent);
+ if( rc==SQLITE_OK ){
+ pMod->parent.xDelete(0);
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ void *pModCtx = (void*)pMod;
+ if( bV2==0 ){
+ fts5_tokenizer t;
+ t.xCreate = f5tTokenizerCreate;
+ t.xTokenize = f5tTokenizerTokenize;
+ t.xDelete = f5tTokenizerDelete;
+ rc = pApi->xCreateTokenizer(pApi, zName, pModCtx, &t, f5tDelTokenizer);
+ }else{
+ fts5_tokenizer_v2 t2;
+ memset(&t2, 0, sizeof(t2));
+ t2.iVersion = iVersion;
+ t2.xCreate = f5tTokenizerCreate;
+ t2.xTokenize = f5tTokenizerTokenize_v2;
+ t2.xDelete = f5tTokenizerDelete;
+ rc = pApi->xCreateTokenizer_v2(pApi, zName, pModCtx, &t2,f5tDelTokenizer);
+ }
+ }
+
if( rc!=SQLITE_OK ){
- Tcl_AppendResult(interp, "error in fts5_api.xCreateTokenizer()", 0);
+ Tcl_AppendResult(interp, (
+ bV2 ? "error in fts5_api.xCreateTokenizer_v2()"
+ : "error in fts5_api.xCreateTokenizer()"
+ ), (char*)0);
return TCL_ERROR;
}
@@ -1048,7 +1320,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
Tcl_Obj *CONST objv[]
){
char *z;
- int n;
+ Tcl_Size n;
unsigned int iVal;
int nSlot;
@@ -1061,7 +1333,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
}
z = Tcl_GetStringFromObj(objv[2], &n);
- iVal = f5t_fts5HashKey(nSlot, z, n);
+ iVal = f5t_fts5HashKey(nSlot, z, (int)n);
Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
return TCL_OK;
}
@@ -1117,6 +1389,313 @@ static int SQLITE_TCLAPI f5tRegisterTok(
return TCL_OK;
}
+typedef struct OriginTextCtx OriginTextCtx;
+struct OriginTextCtx {
+ sqlite3 *db;
+ fts5_api *pApi;
+};
+
+typedef struct OriginTextTokenizer OriginTextTokenizer;
+struct OriginTextTokenizer {
+ Fts5Tokenizer *pTok; /* Underlying tokenizer object */
+ fts5_tokenizer tokapi; /* API implementation for pTok */
+};
+
+/*
+** Delete the OriginTextCtx object indicated by the only argument.
+*/
+static void f5tOrigintextTokenizerDelete(void *pCtx){
+ OriginTextCtx *p = (OriginTextCtx*)pCtx;
+ ckfree((char*)p);
+}
+
+static int f5tOrigintextCreate(
+ void *pCtx,
+ const char **azArg,
+ int nArg,
+ Fts5Tokenizer **ppOut
+){
+ OriginTextCtx *p = (OriginTextCtx*)pCtx;
+ OriginTextTokenizer *pTok = 0;
+ void *pTokCtx = 0;
+ int rc = SQLITE_OK;
+
+ pTok = (OriginTextTokenizer*)sqlite3_malloc(sizeof(OriginTextTokenizer));
+ if( pTok==0 ){
+ rc = SQLITE_NOMEM;
+ }else if( nArg<1 ){
+ rc = SQLITE_ERROR;
+ }else{
+ /* Locate the underlying tokenizer */
+ rc = p->pApi->xFindTokenizer(p->pApi, azArg[0], &pTokCtx, &pTok->tokapi);
+ }
+
+ /* Create the new tokenizer instance */
+ if( rc==SQLITE_OK ){
+ rc = pTok->tokapi.xCreate(pTokCtx, &azArg[1], nArg-1, &pTok->pTok);
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(pTok);
+ pTok = 0;
+ }
+ *ppOut = (Fts5Tokenizer*)pTok;
+ return rc;
+}
+
+static void f5tOrigintextDelete(Fts5Tokenizer *pTokenizer){
+ OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
+ if( p->pTok ){
+ p->tokapi.xDelete(p->pTok);
+ }
+ sqlite3_free(p);
+}
+
+typedef struct OriginTextCb OriginTextCb;
+struct OriginTextCb {
+ void *pCtx;
+ const char *pText;
+ int nText;
+ int (*xToken)(void *, int, const char *, int, int, int);
+
+ char *aBuf; /* Buffer to use */
+ int nBuf; /* Allocated size of aBuf[] */
+};
+
+static int xOriginToken(
+ void *pCtx, /* Copy of 2nd argument to xTokenize() */
+ int tflags, /* Mask of FTS5_TOKEN_* flags */
+ const char *pToken, /* Pointer to buffer containing token */
+ int nToken, /* Size of token in bytes */
+ int iStart, /* Byte offset of token within input text */
+ int iEnd /* Byte offset of end of token within input */
+){
+ OriginTextCb *p = (OriginTextCb*)pCtx;
+ int ret = 0;
+
+ if( nToken==(iEnd-iStart) && 0==memcmp(pToken, &p->pText[iStart], nToken) ){
+ /* Token exactly matches document text. Pass it through as is. */
+ ret = p->xToken(p->pCtx, tflags, pToken, nToken, iStart, iEnd);
+ }else{
+ int nReq = nToken + 1 + (iEnd-iStart);
+ if( nReq>p->nBuf ){
+ sqlite3_free(p->aBuf);
+ p->aBuf = sqlite3_malloc(nReq*2);
+ if( p->aBuf==0 ) return SQLITE_NOMEM;
+ p->nBuf = nReq*2;
+ }
+
+ memcpy(p->aBuf, pToken, nToken);
+ p->aBuf[nToken] = '\0';
+ memcpy(&p->aBuf[nToken+1], &p->pText[iStart], iEnd-iStart);
+ ret = p->xToken(p->pCtx, tflags, p->aBuf, nReq, iStart, iEnd);
+ }
+
+ return ret;
+}
+
+
+static int f5tOrigintextTokenize(
+ Fts5Tokenizer *pTokenizer,
+ void *pCtx,
+ int flags, /* Mask of FTS5_TOKENIZE_* flags */
+ const char *pText, int nText,
+ int (*xToken)(void *, int, const char *, int, int, int)
+){
+ OriginTextTokenizer *p = (OriginTextTokenizer*)pTokenizer;
+ OriginTextCb cb;
+ int ret;
+
+ memset(&cb, 0, sizeof(cb));
+ cb.pCtx = pCtx;
+ cb.pText = pText;
+ cb.nText = nText;
+ cb.xToken = xToken;
+
+ ret = p->tokapi.xTokenize(p->pTok,(void*)&cb,flags,pText,nText,xOriginToken);
+ sqlite3_free(cb.aBuf);
+ return ret;
+}
+
+/*
+** sqlite3_fts5_register_origintext DB
+**
+** Description...
+*/
+static int SQLITE_TCLAPI f5tRegisterOriginText(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db = 0;
+ fts5_api *pApi = 0;
+ int rc;
+ fts5_tokenizer tok = {0, 0, 0};
+ OriginTextCtx *pCtx = 0;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB");
+ return TCL_ERROR;
+ }
+ if( f5tDbAndApi(interp, objv[1], &db, &pApi) ) return TCL_ERROR;
+
+ pCtx = (OriginTextCtx*)ckalloc(sizeof(OriginTextCtx));
+ pCtx->db = db;
+ pCtx->pApi = pApi;
+
+ tok.xCreate = f5tOrigintextCreate;
+ tok.xDelete = f5tOrigintextDelete;
+ tok.xTokenize = f5tOrigintextTokenize;
+ rc = pApi->xCreateTokenizer(
+ pApi, "origintext", (void*)pCtx, &tok, f5tOrigintextTokenizerDelete
+ );
+
+ Tcl_ResetResult(interp);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
+ return TCL_ERROR;
+ }
+ return TCL_OK;
+}
+
+/*
+** This function is used to DROP an fts5 table. It works even if the data
+** structures fts5 stores within the database are corrupt, which sometimes
+** prevents a straight "DROP TABLE" command from succeeding.
+**
+** The first parameter is the database handle to use for the DROP TABLE
+** operation. The second is the name of the database to drop the fts5 table
+** from (i.e. "main", "temp" or the name of an attached database). The
+** third parameter is the name of the fts5 table to drop.
+**
+** SQLITE_OK is returned if the table is successfully dropped. Or, if an
+** error occurs, an SQLite error code.
+*/
+static int sqlite3_fts5_drop_corrupt_table(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Database name ("main", "temp" etc.) */
+ const char *zTab /* Name of fts5 table to drop */
+){
+ int rc = SQLITE_OK;
+ int bDef = 0;
+
+ rc = sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, -1, &bDef);
+ if( rc==SQLITE_OK ){
+ char *zScript = sqlite3_mprintf(
+ "DELETE FROM %Q.'%q_data';"
+ "DELETE FROM %Q.'%q_config';"
+ "INSERT INTO %Q.'%q_data' VALUES(10, X'0000000000');"
+ "INSERT INTO %Q.'%q_config' VALUES('version', 4);"
+ "DROP TABLE %Q.'%q';",
+ zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab, zDb, zTab
+ );
+
+ if( zScript==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 0, 0);
+ rc = sqlite3_exec(db, zScript, 0, 0, 0);
+ if( bDef ) sqlite3_db_config(db, SQLITE_DBCONFIG_DEFENSIVE, 1, 0);
+ sqlite3_free(zScript);
+ }
+ }
+
+ return rc;
+}
+
+/*
+** sqlite3_fts5_drop_corrupt_table DB DATABASE TABLE
+**
+** Description...
+*/
+static int SQLITE_TCLAPI f5tDropCorruptTable(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db = 0;
+ const char *zDb = 0;
+ const char *zTab = 0;
+ int rc = SQLITE_OK;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DATABASE TABLE");
+ return TCL_ERROR;
+ }
+ if( f5tDbPointer(interp, objv[1], &db) ){
+ return TCL_ERROR;
+ }
+ zDb = Tcl_GetString(objv[2]);
+ zTab = Tcl_GetString(objv[3]);
+
+ rc = sqlite3_fts5_drop_corrupt_table(db, zDb, zTab);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), (void*)0);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/*
+** Free a buffer returned to SQLite by the str() function.
+*/
+void f5tFree(void *p){
+ char *x = (char *)p;
+ ckfree(&x[-8]);
+}
+
+/*
+** Implementation of str().
+*/
+void f5tStrFunc(sqlite3_context *pCtx, int nArg, sqlite3_value **apArg){
+ const char *zText = 0;
+ assert( nArg==1 );
+
+ zText = (const char*)sqlite3_value_text(apArg[0]);
+ if( zText ){
+ sqlite3_int64 nText = strlen(zText);
+ char *zCopy = (char*)ckalloc(nText+8);
+ if( zCopy==0 ){
+ sqlite3_result_error_nomem(pCtx);
+ }else{
+ zCopy += 8;
+ memcpy(zCopy, zText, nText);
+ sqlite3_result_text64(pCtx, zCopy, nText, f5tFree, SQLITE_UTF8);
+ }
+ }
+}
+
+/*
+** sqlite3_fts5_register_str DB
+**
+** Register the str() function with database handle DB. str() interprets
+** its only argument as text and returns a copy of the value in a
+** non-nul-terminated buffer.
+*/
+static int SQLITE_TCLAPI f5tRegisterStr(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db = 0;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB");
+ return TCL_ERROR;
+ }
+ if( f5tDbPointer(interp, objv[1], &db) ){
+ return TCL_ERROR;
+ }
+
+ sqlite3_create_function(db, "str", 1, SQLITE_UTF8, 0, f5tStrFunc, 0, 0);
+
+ return TCL_OK;
+}
+
/*
** Entry point.
*/
@@ -1128,12 +1707,16 @@ int Fts5tcl_Init(Tcl_Interp *interp){
} aCmd[] = {
{ "sqlite3_fts5_create_tokenizer", f5tCreateTokenizer, 1 },
{ "sqlite3_fts5_token", f5tTokenizerReturn, 1 },
+ { "sqlite3_fts5_locale", f5tTokenizerLocale, 1 },
{ "sqlite3_fts5_tokenize", f5tTokenize, 0 },
{ "sqlite3_fts5_create_function", f5tCreateFunction, 0 },
{ "sqlite3_fts5_may_be_corrupt", f5tMayBeCorrupt, 0 },
{ "sqlite3_fts5_token_hash", f5tTokenHash, 0 },
{ "sqlite3_fts5_register_matchinfo", f5tRegisterMatchinfo, 0 },
- { "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 }
+ { "sqlite3_fts5_register_fts5tokenize", f5tRegisterTok, 0 },
+ { "sqlite3_fts5_register_origintext",f5tRegisterOriginText, 0 },
+ { "sqlite3_fts5_drop_corrupt_table", f5tDropCorruptTable, 0 },
+ { "sqlite3_fts5_register_str", f5tRegisterStr, 0 }
};
int i;
F5tTokenizerContext *pContext;
diff --git a/ext/fts5/fts5_tokenize.c b/ext/fts5/fts5_tokenize.c
index e61d6b1edd..b8a1136465 100644
--- a/ext/fts5/fts5_tokenize.c
+++ b/ext/fts5/fts5_tokenize.c
@@ -198,7 +198,7 @@ static const unsigned char sqlite3Utf8Trans1[] = {
c = *(zIn++); \
if( c>=0xc0 ){ \
c = sqlite3Utf8Trans1[c-0xc0]; \
- while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \
+ while( zIn=0xc0 ){ \
+ while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
+
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -380,7 +386,6 @@ static int fts5UnicodeCreate(
zCat = azArg[i+1];
}
}
-
if( rc==SQLITE_OK ){
rc = unicodeSetCategories(p, zCat);
}
@@ -410,7 +415,6 @@ static int fts5UnicodeCreate(
rc = SQLITE_ERROR;
}
}
-
}else{
rc = SQLITE_NOMEM;
}
@@ -549,7 +553,7 @@ static int fts5UnicodeTokenize(
typedef struct PorterTokenizer PorterTokenizer;
struct PorterTokenizer {
- fts5_tokenizer tokenizer; /* Parent tokenizer module */
+ fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */
Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */
char aBuf[FTS5_PORTER_MAX_TOKEN + 64];
};
@@ -561,7 +565,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
if( pTok ){
PorterTokenizer *p = (PorterTokenizer*)pTok;
if( p->pTokenizer ){
- p->tokenizer.xDelete(p->pTokenizer);
+ p->tokenizer_v2.xDelete(p->pTokenizer);
}
sqlite3_free(p);
}
@@ -580,6 +584,7 @@ static int fts5PorterCreate(
PorterTokenizer *pRet;
void *pUserdata = 0;
const char *zBase = "unicode61";
+ fts5_tokenizer_v2 *pV2 = 0;
if( nArg>0 ){
zBase = azArg[0];
@@ -588,14 +593,15 @@ static int fts5PorterCreate(
pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer));
if( pRet ){
memset(pRet, 0, sizeof(PorterTokenizer));
- rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer);
+ rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2);
}else{
rc = SQLITE_NOMEM;
}
if( rc==SQLITE_OK ){
int nArg2 = (nArg>0 ? nArg-1 : 0);
- const char **azArg2 = (nArg2 ? &azArg[1] : 0);
- rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer);
+ const char **az2 = (nArg2 ? &azArg[1] : 0);
+ memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2));
+ rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer);
}
if( rc!=SQLITE_OK ){
@@ -1246,6 +1252,7 @@ static int fts5PorterTokenize(
void *pCtx,
int flags,
const char *pText, int nText,
+ const char *pLoc, int nLoc,
int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd)
){
PorterTokenizer *p = (PorterTokenizer*)pTokenizer;
@@ -1253,8 +1260,8 @@ static int fts5PorterTokenize(
sCtx.xToken = xToken;
sCtx.pCtx = pCtx;
sCtx.aBuf = p->aBuf;
- return p->tokenizer.xTokenize(
- p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb
+ return p->tokenizer_v2.xTokenize(
+ p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb
);
}
@@ -1264,6 +1271,7 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
+ int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -1283,28 +1291,46 @@ static int fts5TriCreate(
Fts5Tokenizer **ppOut
){
int rc = SQLITE_OK;
- TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
+ TrigramTokenizer *pNew = 0;
UNUSED_PARAM(pUnused);
- if( pNew==0 ){
- rc = SQLITE_NOMEM;
+ if( nArg%2 ){
+ rc = SQLITE_ERROR;
}else{
int i;
- pNew->bFold = 1;
- for(i=0; rc==SQLITE_OK && ibFold = 1;
+ pNew->iFoldParam = 0;
+
+ for(i=0; rc==SQLITE_OK && ibFold = (zArg[0]=='0');
+ }
+ }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
+ }
}else{
- pNew->bFold = (zArg[0]=='0');
+ rc = SQLITE_ERROR;
}
- }else{
+ }
+
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
- }
- if( rc!=SQLITE_OK ){
- fts5TriDelete((Fts5Tokenizer*)pNew);
- pNew = 0;
+
+ if( rc!=SQLITE_OK ){
+ fts5TriDelete((Fts5Tokenizer*)pNew);
+ pNew = 0;
+ }
}
}
*ppOut = (Fts5Tokenizer*)pNew;
@@ -1324,40 +1350,65 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
+ char *zOut = aBuf;
+ int ii;
const unsigned char *zIn = (const unsigned char*)pText;
- const unsigned char *zEof = &zIn[nText];
- u32 iCode;
+ const unsigned char *zEof = (zIn ? &zIn[nText] : 0);
+ u32 iCode = 0;
+ int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
- while( 1 ){
- char *zOut = aBuf;
- int iStart = zIn - (const unsigned char*)pText;
- const unsigned char *zNext;
-
- READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- zNext = zIn;
- if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+
+ /* Populate aBuf[] with the characters for the first trigram. */
+ for(ii=0; ii<3; ii++){
+ do {
+ aStart[ii] = zIn - (const unsigned char*)pText;
+ if( zIn>=zEof ) return SQLITE_OK;
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- }else{
- break;
- }
- if( zInbFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+ WRITE_UTF8(zOut, iCode);
+ }
+
+ /* At the start of each iteration of this loop:
+ **
+ ** aBuf: Contains 3 characters. The 3 characters of the next trigram.
+ ** zOut: Points to the byte following the last character in aBuf.
+ ** aStart[3]: Contains the byte offset in the input text corresponding
+ ** to the start of each of the three characters in the buffer.
+ */
+ assert( zIn<=zEof );
+ while( 1 ){
+ int iNext; /* Start of character following current tri */
+ const char *z1;
+
+ /* Read characters from the input up until the first non-diacritic */
+ do {
+ iNext = zIn - (const unsigned char*)pText;
+ if( zIn>=zEof ){
+ iCode = 0;
+ break;
+ }
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
- }else{
- break;
- }
- rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
- if( rc!=SQLITE_OK ) break;
- zIn = zNext;
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+
+ /* Pass the current trigram back to fts5 */
+ rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
+ if( iCode==0 || rc!=SQLITE_OK ) break;
+
+ /* Remove the first character from buffer aBuf[]. Append the character
+ ** with codepoint iCode. */
+ z1 = aBuf;
+ FTS5_SKIP_UTF8(z1);
+ memmove(aBuf, z1, zOut - z1);
+ zOut -= (z1 - aBuf);
+ WRITE_UTF8(zOut, iCode);
+
+ /* Update the aStart[] array */
+ aStart[0] = aStart[1];
+ aStart[1] = aStart[2];
+ aStart[2] = iNext;
}
return rc;
@@ -1380,11 +1431,23 @@ int sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
- return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ if( p->iFoldParam==0 ){
+ return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ }
}
return FTS5_PATTERN_NONE;
}
+/*
+** Return true if the tokenizer described by p->azArg[] is the trigram
+** tokenizer. This tokenizer needs to be loaded before xBestIndex is
+** called for the first time in order to correctly handle LIKE/GLOB.
+*/
+int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig *p){
+ return (p->nArg>=1 && 0==sqlite3_stricmp(p->azArg[0], "trigram"));
+}
+
+
/*
** Register all built-in tokenizers with FTS5.
*/
@@ -1395,7 +1458,6 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
} aBuiltin[] = {
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
- { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
{ "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
};
@@ -1410,6 +1472,19 @@ int sqlite3Fts5TokenizerInit(fts5_api *pApi){
0
);
}
-
+ if( rc==SQLITE_OK ){
+ fts5_tokenizer_v2 sPorter = {
+ 2,
+ fts5PorterCreate,
+ fts5PorterDelete,
+ fts5PorterTokenize
+ };
+ rc = pApi->xCreateTokenizer_v2(pApi,
+ "porter",
+ (void*)pApi,
+ &sPorter,
+ 0
+ );
+ }
return rc;
}
diff --git a/ext/fts5/fts5_unicode2.c b/ext/fts5/fts5_unicode2.c
index 3e97264fa8..cc164a4569 100644
--- a/ext/fts5/fts5_unicode2.c
+++ b/ext/fts5/fts5_unicode2.c
@@ -364,6 +364,9 @@ int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
default: return 1; }
break;
+
+ default:
+ return 1;
}
return 0;
}
diff --git a/ext/fts5/fts5_vocab.c b/ext/fts5/fts5_vocab.c
index d738ada311..fb280567f4 100644
--- a/ext/fts5/fts5_vocab.c
+++ b/ext/fts5/fts5_vocab.c
@@ -64,6 +64,7 @@ struct Fts5VocabCursor {
int nLeTerm; /* Size of zLeTerm in bytes */
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
+ int colUsed; /* Copy of sqlite3_index_info.colUsed */
/* These are used by 'col' tables only */
int iCol;
@@ -90,9 +91,11 @@ struct Fts5VocabCursor {
/*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
*/
-#define FTS5_VOCAB_TERM_EQ 0x01
-#define FTS5_VOCAB_TERM_GE 0x02
-#define FTS5_VOCAB_TERM_LE 0x04
+#define FTS5_VOCAB_TERM_EQ 0x0100
+#define FTS5_VOCAB_TERM_GE 0x0200
+#define FTS5_VOCAB_TERM_LE 0x0400
+
+#define FTS5_VOCAB_COLUSED_MASK 0xFF
/*
@@ -269,11 +272,13 @@ static int fts5VocabBestIndexMethod(
int iTermEq = -1;
int iTermGe = -1;
int iTermLe = -1;
- int idxNum = 0;
+ int idxNum = (int)pInfo->colUsed;
int nArg = 0;
UNUSED_PARAM(pUnused);
+ assert( (pInfo->colUsed & FTS5_VOCAB_COLUSED_MASK)==pInfo->colUsed );
+
for(i=0; inConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
if( p->usable==0 ) continue;
@@ -365,7 +370,7 @@ static int fts5VocabOpenMethod(
if( rc==SQLITE_OK ){
pVTab->zErrMsg = sqlite3_mprintf(
"no such fts5 table: %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
- );
+ );
rc = SQLITE_ERROR;
}
}else{
@@ -525,9 +530,19 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
switch( pTab->eType ){
case FTS5_VOCAB_ROW:
- if( eDetail==FTS5_DETAIL_FULL ){
- while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){
- pCsr->aCnt[0]++;
+ /* Do not bother counting the number of instances if the "cnt"
+ ** column is not being read (according to colUsed). */
+ if( eDetail==FTS5_DETAIL_FULL && (pCsr->colUsed & 0x04) ){
+ while( iPosaCnt[] */
+ pCsr->aCnt[0]++;
+ }
}
}
pCsr->aDoc[0]++;
@@ -625,11 +640,12 @@ static int fts5VocabFilterMethod(
if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
+ pCsr->colUsed = (idxNum & FTS5_VOCAB_COLUSED_MASK);
if( pEq ){
zTerm = (const char *)sqlite3_value_text(pEq);
nTerm = sqlite3_value_bytes(pEq);
- f = 0;
+ f = FTS5INDEX_QUERY_NOTOKENDATA;
}else{
if( pGe ){
zTerm = (const char *)sqlite3_value_text(pGe);
diff --git a/ext/fts5/test/fts5_common.tcl b/ext/fts5/test/fts5_common.tcl
index 9c012932da..8ea87dbdd1 100644
--- a/ext/fts5/test/fts5_common.tcl
+++ b/ext/fts5/test/fts5_common.tcl
@@ -51,6 +51,10 @@ proc fts5_test_poslist2 {cmd} {
sort_poslist $res
}
+proc fts5_test_insttoken {cmd iInst iToken} {
+ $cmd xInstToken $iInst $iToken
+}
+
proc fts5_test_collist {cmd} {
set res [list]
@@ -61,6 +65,12 @@ proc fts5_test_collist {cmd} {
set res
}
+proc fts5_collist {cmd iPhrase} {
+ set res [list]
+ $cmd xPhraseColumnForeach $iPhrase c { lappend res $c }
+ set res
+}
+
proc fts5_test_columnsize {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -69,6 +79,13 @@ proc fts5_test_columnsize {cmd} {
set res
}
+proc fts5_columntext {cmd iCol} {
+ $cmd xColumnText $iCol
+}
+proc fts5_columnlocale {cmd iCol} {
+ $cmd xColumnLocale $iCol
+}
+
proc fts5_test_columntext {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -77,6 +94,14 @@ proc fts5_test_columntext {cmd} {
set res
}
+proc fts5_test_columnlocale {cmd} {
+ set res [list]
+ for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
+ lappend res [$cmd xColumnLocale $i]
+ }
+ set res
+}
+
proc fts5_test_columntotalsize {cmd} {
set res [list]
for {set i 0} {$i < [$cmd xColumnCount]} {incr i} {
@@ -104,6 +129,10 @@ proc fts5_test_rowcount {cmd} {
$cmd xRowCount
}
+proc fts5_test_rowid {cmd} {
+ $cmd xRowid
+}
+
proc test_queryphrase_cb {cnt cmd} {
upvar $cnt L
for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
@@ -125,6 +154,13 @@ proc fts5_test_queryphrase {cmd} {
set res
}
+proc fts5_queryphrase {cmd iPhrase} {
+ set cnt [list]
+ for {set j 0} {$j < [$cmd xColumnCount]} {incr j} { lappend cnt 0 }
+ $cmd xQueryPhrase $iPhrase [list test_queryphrase_cb cnt]
+ set cnt
+}
+
proc fts5_test_phrasecount {cmd} {
$cmd xPhraseCount
}
@@ -144,16 +180,23 @@ proc fts5_aux_test_functions {db} {
foreach f {
fts5_test_columnsize
fts5_test_columntext
+ fts5_test_columnlocale
fts5_test_columntotalsize
fts5_test_poslist
fts5_test_poslist2
fts5_test_collist
+ fts5_test_insttoken
fts5_test_tokenize
fts5_test_rowcount
+ fts5_test_rowid
fts5_test_all
fts5_test_queryphrase
fts5_test_phrasecount
+ fts5_columntext
+ fts5_columnlocale
+ fts5_queryphrase
+ fts5_collist
} {
sqlite3_fts5_create_function $db $f $f
}
@@ -438,6 +481,20 @@ proc detail_is_none {} { detail_check ; expr {$::detail == "none"} }
proc detail_is_col {} { detail_check ; expr {$::detail == "col" } }
proc detail_is_full {} { detail_check ; expr {$::detail == "full"} }
+proc foreach_tokenizer_mode {prefix script} {
+ set saved $::testprefix
+ foreach {d mapping} {
+ "" {}
+ "-origintext" {, tokenize="origintext unicode61", tokendata=1}
+ } {
+ set s [string map [list %TOKENIZER% $mapping] $script]
+ set ::testprefix "$prefix$d"
+ reset_db
+ sqlite3_fts5_register_origintext db
+ uplevel $s
+ }
+ set ::testprefix $saved
+}
#-------------------------------------------------------------------------
# Convert a poslist of the type returned by fts5_test_poslist() to a
diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test
index e1551fc516..bcad9e7241 100644
--- a/ext/fts5/test/fts5aa.test
+++ b/ext/fts5/test/fts5aa.test
@@ -22,6 +22,7 @@ ifcapable !fts5 {
}
foreach_detail_mode $::testprefix {
+foreach_tokenizer_mode $::testprefix {
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
@@ -44,7 +45,7 @@ do_execsql_test 1.1 {
#
do_execsql_test 2.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
}
do_execsql_test 2.1 {
INSERT INTO t1 VALUES('a b c', 'd e f');
@@ -73,8 +74,9 @@ do_execsql_test 2.4 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 3.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
}
foreach {i x y} {
1 {g f d b f} {h h e i a}
@@ -97,8 +99,9 @@ foreach {i x y} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 4.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
foreach {i x y} {
@@ -121,8 +124,9 @@ foreach {i x y} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 5.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
foreach {i x y} {
@@ -145,8 +149,9 @@ foreach {i x y} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 6.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
}
@@ -181,6 +186,7 @@ do_execsql_test 6.6 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
expr srand(0)
do_execsql_test 7.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x,y,z);
@@ -222,6 +228,7 @@ for {set i 1} {$i <= 10} {incr i} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 8.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, prefix="1,2,3");
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
@@ -236,6 +243,7 @@ do_execsql_test 8.1 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
expr srand(0)
@@ -280,8 +288,9 @@ for {set i 1} {$i <= 10} {incr i} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 10.0 {
- CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
}
set d10 {
1 {g f d b f} {h h e i a}
@@ -314,19 +323,19 @@ do_execsql_test 10.4.2 { INSERT INTO t1(t1) VALUES('integrity-check') }
#-------------------------------------------------------------------------
#
do_catchsql_test 11.1 {
- CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rank, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 column name: rank}}
do_catchsql_test 11.2 {
- CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE rank USING fts5(a, b, c, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 table name: rank}}
do_catchsql_test 11.3 {
- CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t2 USING fts5(a, b, c, rowid, detail=%DETAIL% %TOKENIZER%);
} {1 {reserved fts5 column name: rowid}}
#-------------------------------------------------------------------------
#
do_execsql_test 12.1 {
- CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t2 USING fts5(x,y, detail=%DETAIL% %TOKENIZER%);
} {}
do_catchsql_test 12.2 {
@@ -341,8 +350,9 @@ do_test 12.3 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 13.1 {
- CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1(rowid, x) VALUES(1, 'o n e'), (2, 't w o');
} {}
@@ -365,8 +375,9 @@ do_execsql_test 13.6 {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 14.1 {
- CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
WITH d(x,y) AS (
SELECT NULL, 'xyz xyz xyz xyz xyz xyz'
@@ -429,7 +440,7 @@ do_execsql_test 16.1 {
proc funk {} {
db eval { UPDATE n1_config SET v=50 WHERE k='version' }
set fd [db incrblob main n1_data block 10]
- fconfigure $fd -encoding binary -translation binary
+ fconfigure $fd -translation binary
# puts -nonewline $fd "\x44\x45"
close $fd
}
@@ -442,15 +453,16 @@ db func funk funk
# statement no longer fails.
#
do_catchsql_test 16.2 {
- SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
+ SELECT funk(), format('%g',bm25(n1)), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}}
# {1 {SQL logic error}}
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 17.1 {
- CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE b2 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
INSERT INTO b2 VALUES('a');
INSERT INTO b2 VALUES('b');
INSERT INTO b2 VALUES('c');
@@ -466,8 +478,9 @@ do_test 17.2 {
if {[string match n* %DETAIL%]==0} {
reset_db
+ sqlite3_fts5_register_origintext db
do_execsql_test 17.3 {
- CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE c2 USING fts5(x, y, detail=%DETAIL% %TOKENIZER%);
INSERT INTO c2 VALUES('x x x', 'x x x');
SELECT rowid FROM c2 WHERE c2 MATCH 'y:x';
} {1}
@@ -476,8 +489,9 @@ if {[string match n* %DETAIL%]==0} {
#-------------------------------------------------------------------------
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 17.1 {
- CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE uio USING fts5(ttt, detail=%DETAIL% %TOKENIZER%);
INSERT INTO uio VALUES(NULL);
INSERT INTO uio SELECT NULL FROM uio;
INSERT INTO uio SELECT NULL FROM uio;
@@ -524,8 +538,8 @@ do_execsql_test 17.9 {
#--------------------------------------------------------------------
#
do_execsql_test 18.1 {
- CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL%);
- CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b, detail=%DETAIL% %TOKENIZER%);
+ CREATE VIRTUAL TABLE t2 USING fts5(c, d, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1 VALUES('abc*', NULL);
INSERT INTO t2 VALUES(1, 'abcdefg');
}
@@ -540,8 +554,9 @@ do_execsql_test 18.3 {
# fts5 table in the temp schema.
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 19.0 {
- CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE temp.t1 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t1 VALUES('x y z');
INSERT INTO t1 VALUES('w x 1');
SELECT rowid FROM t1 WHERE t1 MATCH 'x';
@@ -551,8 +566,9 @@ do_execsql_test 19.0 {
# Test that 6 and 7 byte varints can be read.
#
reset_db
+sqlite3_fts5_register_origintext db
do_execsql_test 20.0 {
- CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE temp.tmp USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}
set ::ids [list \
0 [expr 1<<36] [expr 2<<36] [expr 1<<43] [expr 2<<43]
@@ -570,7 +586,7 @@ do_test 20.1 {
#
do_execsql_test 21.0 {
CREATE TEMP TABLE t8(a, b);
- CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}
do_execsql_test 21.1 {
@@ -581,7 +597,7 @@ do_execsql_test 21.1 {
}
do_execsql_test 22.0 {
- CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t9 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t9(rowid, x) VALUES(2, 'bbb');
BEGIN;
INSERT INTO t9(rowid, x) VALUES(1, 'aaa');
@@ -596,7 +612,7 @@ do_execsql_test 22.1 {
#-------------------------------------------------------------------------
do_execsql_test 23.0 {
- CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t10 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
CREATE TABLE t11(x);
}
do_execsql_test 23.1 {
@@ -608,7 +624,7 @@ do_execsql_test 23.2 {
#-------------------------------------------------------------------------
do_execsql_test 24.0 {
- CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t12 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
INSERT INTO t12 VALUES('aaaa');
}
do_execsql_test 24.1 {
@@ -618,6 +634,9 @@ do_execsql_test 24.1 {
INSERT INTO t12 VALUES('aaaa');
END;
}
+execsql_pp {
+ SELECT rowid, hex(block) FROM t12_data
+}
do_execsql_test 24.2 {
INSERT INTO t12(t12) VALUES('integrity-check');
}
@@ -627,7 +646,7 @@ do_execsql_test 24.3 {
#-------------------------------------------------------------------------
do_execsql_test 25.0 {
- CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL%);
+ CREATE VIRTUAL TABLE t13 USING fts5(x, detail=%DETAIL% %TOKENIZER%);
}
do_execsql_test 25.1 {
BEGIN;
@@ -638,6 +657,7 @@ SELECT * FROM t13('BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
}
+}
}
expand_all_sql db
diff --git a/ext/fts5/test/fts5ab.test b/ext/fts5/test/fts5ab.test
index 5aa7456586..7e312286f3 100644
--- a/ext/fts5/test/fts5ab.test
+++ b/ext/fts5/test/fts5ab.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ab
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ac.test b/ext/fts5/test/fts5ac.test
index f3a914653f..4628e909c1 100644
--- a/ext/fts5/test/fts5ac.test
+++ b/ext/fts5/test/fts5ac.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ac
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ad.test b/ext/fts5/test/fts5ad.test
index 524da6deae..27806a4c0c 100644
--- a/ext/fts5/test/fts5ad.test
+++ b/ext/fts5/test/fts5ad.test
@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ad
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ae.test b/ext/fts5/test/fts5ae.test
index d9f132ca97..205a59a69f 100644
--- a/ext/fts5/test/fts5ae.test
+++ b/ext/fts5/test/fts5ae.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ae
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5af.test b/ext/fts5/test/fts5af.test
index 3d79295092..9c95ef2daa 100644
--- a/ext/fts5/test/fts5af.test
+++ b/ext/fts5/test/fts5af.test
@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5af
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ag.test b/ext/fts5/test/fts5ag.test
index 9ead957c9d..42cd913784 100644
--- a/ext/fts5/test/fts5ag.test
+++ b/ext/fts5/test/fts5ag.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ag
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ah.test b/ext/fts5/test/fts5ah.test
index 0004351375..bf9c9e9dbc 100644
--- a/ext/fts5/test/fts5ah.test
+++ b/ext/fts5/test/fts5ah.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ah
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -163,6 +163,17 @@ do_execsql_test 1.8.2 {
SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid < 'text';
} {10000}
+do_execsql_test 1.8.3 {
+ SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid<5000 AND rowid < 'text';
+} {4999}
+do_execsql_test 1.8.4 {
+ SELECT count(*) FROM t1 WHERE t1 MATCH 'x' AND rowid>5000 AND rowid > 'text';
+} {0}
+
+do_catchsql_test 1.9 {
+ SELECT * FROM t1('*xy');
+} {1 {unknown special query: xy}}
+
} ;# foreach_detail_mode
#db eval {SELECT rowid, fts5_decode(rowid, block) aS r FROM t1_data} {puts $r}
diff --git a/ext/fts5/test/fts5ai.test b/ext/fts5/test/fts5ai.test
index 20e1069398..a6576d3afc 100644
--- a/ext/fts5/test/fts5ai.test
+++ b/ext/fts5/test/fts5ai.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ai
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5aj.test b/ext/fts5/test/fts5aj.test
index 50dae20162..e802306b38 100644
--- a/ext/fts5/test/fts5aj.test
+++ b/ext/fts5/test/fts5aj.test
@@ -19,7 +19,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aj
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5ak.test b/ext/fts5/test/fts5ak.test
index e248f2a328..253f14fc79 100644
--- a/ext/fts5/test/fts5ak.test
+++ b/ext/fts5/test/fts5ak.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ak
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5al.test b/ext/fts5/test/fts5al.test
index 842d991a37..7187ad67c7 100644
--- a/ext/fts5/test/fts5al.test
+++ b/ext/fts5/test/fts5al.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5al
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -293,6 +293,16 @@ do_catchsql_test 4.4.4 {
SELECT *, rank FROM t3 WHERE t3 MATCH 'a' AND rank MATCH NULL
} {1 {parse error in rank function: }}
+# Check that the second and subsequent rank= constraints are ignored.
+#
+do_catchsql_test 4.3.3 {
+ SELECT *, rank FROM t3
+ WHERE t3 MATCH 'a' AND
+ rank MATCH 'nosuch()' AND
+ rank MATCH 'rowidmod(3)'
+ ORDER BY rank ASC
+} {1 {unable to use function MATCH in the requested context}}
+
} ;# foreach_detail_mode
diff --git a/ext/fts5/test/fts5alter.test b/ext/fts5/test/fts5alter.test
index 67f948cbbe..bb5f78dc86 100644
--- a/ext/fts5/test/fts5alter.test
+++ b/ext/fts5/test/fts5alter.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5alter
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5auto.test b/ext/fts5/test/fts5auto.test
index 79d432b812..b771af912e 100644
--- a/ext/fts5/test/fts5auto.test
+++ b/ext/fts5/test/fts5auto.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5auto
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5aux.test b/ext/fts5/test/fts5aux.test
index b5a13aea1a..960dbc5117 100644
--- a/ext/fts5/test/fts5aux.test
+++ b/ext/fts5/test/fts5aux.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aux
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -334,4 +334,71 @@ do_execsql_test 11.2 {
SELECT fts5_hitcount(x1) FROM x1('one') LIMIT 1;
} {5}
+#-------------------------------------------------------------------------
+# Test that xColumnText returns SQLITE_RANGE when it should.
+#
+reset_db
+fts5_aux_test_functions db
+do_execsql_test 12.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
+ INSERT INTO t1 VALUES('one', 'two', 'three');
+ INSERT INTO t1 VALUES('one', 'one', 'one');
+ INSERT INTO t1 VALUES('two', 'two', 'two');
+ INSERT INTO t1 VALUES('three', 'three', 'three');
+}
+
+do_catchsql_test 12.1.1 {
+ SELECT fts5_columntext(t1, -1) FROM t1('two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.1.2 {
+ SELECT fts5_columntext(t1, 3) FROM t1('two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.1.2 {
+ SELECT fts5_columntext(t1, 1) FROM t1('one AND two');
+} {0 two}
+
+do_catchsql_test 12.2.1 {
+ SELECT fts5_queryphrase(t1, -1) FROM t1('one AND two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.2.2 {
+ SELECT fts5_queryphrase(t1, 2) FROM t1('one AND two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.2.3 {
+ SELECT fts5_queryphrase(t1, 1) FROM t1('one AND two');
+} {0 {{1 2 1}}}
+
+do_catchsql_test 12.3.1 {
+ SELECT fts5_collist(t1, -1) FROM t1('one AND two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.3.2 {
+ SELECT fts5_collist(t1, 2) FROM t1('one AND two');
+} {1 SQLITE_RANGE}
+do_catchsql_test 12.3.3 {
+ SELECT fts5_collist(t1, 1) FROM t1('one AND two');
+} {0 1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 13.1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=ascii);
+ INSERT INTO t1 VALUES('a b c'), ('d e f');
+ PRAGMA integrity_check;
+} {ok}
+
+do_catchsql_test 13.2 {
+ SELECT highlight(t1, 0, '[', ']') FROM t1
+} {0 {{a b c} {d e f}}}
+
+do_execsql_test 13.3 {
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_schema SET sql = 'CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=blah)'
+ WHERE name = 't1';
+}
+
+db close
+sqlite3 db test.db
+do_catchsql_test 13.4 {
+ SELECT highlight(t1, 0, '[', ']') FROM t1
+} {1 {SQL logic error}}
+
finish_test
diff --git a/ext/fts5/test/fts5aux2.test b/ext/fts5/test/fts5aux2.test
new file mode 100644
index 0000000000..2352970ec7
--- /dev/null
+++ b/ext/fts5/test/fts5aux2.test
@@ -0,0 +1,71 @@
+# 2024 June 24
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focusing on the auxiliary function APIs.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5aux
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(a, b);
+ INSERT INTO x1 VALUES('a b', 'c d');
+ INSERT INTO x1 VALUES('d e', 'a b');
+ INSERT INTO x1 VALUES('a b', 'e f');
+ INSERT INTO x1 VALUES('d e', 'c d');
+}
+
+fts5_aux_test_functions db
+do_execsql_test 1.1 {
+ SELECT fts5_test_all(x1) FROM x1 WHERE rowid=2
+} [list [list {*}{
+ columnsize {2 2}
+ columntext {{d e} {a b}}
+ columntotalsize {8 8}
+ poslist {}
+ tokenize {{d e} {a b}}
+ rowcount 4
+}]]
+
+do_execsql_test 1.2 {
+ SELECT fts5_test_columntext(x1) FROM x1
+} {
+ {{a b} {c d}}
+ {{d e} {a b}}
+ {{a b} {e f}}
+ {{d e} {c d}}
+}
+
+do_execsql_test 1.3 {
+ SELECT fts5_test_rowid(x1) FROM x1
+} {
+ 1 2 3 4
+}
+do_execsql_test 1.4 {
+ SELECT fts5_test_phrasecount(x1) FROM x1
+} {
+ 0 0 0 0
+}
+do_catchsql_test 1.5 {
+ SELECT fts5_queryphrase(x1, 0) FROM x1
+} {1 SQLITE_RANGE}
+do_execsql_test 1.6 {
+ SELECT fts5_test_rowcount(x1) FROM x1
+} {4 4 4 4}
+
+
+finish_test
diff --git a/ext/fts5/test/fts5auxdata.test b/ext/fts5/test/fts5auxdata.test
index a2a41704c5..7f99fed316 100644
--- a/ext/fts5/test/fts5auxdata.test
+++ b/ext/fts5/test/fts5auxdata.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5auxdata
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5bigpl.test b/ext/fts5/test/fts5bigpl.test
index 2c9df11b1f..9e3d86c0e6 100644
--- a/ext/fts5/test/fts5bigpl.test
+++ b/ext/fts5/test/fts5bigpl.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5bigpl
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5blob.test b/ext/fts5/test/fts5blob.test
new file mode 100644
index 0000000000..9348554104
--- /dev/null
+++ b/ext/fts5/test/fts5blob.test
@@ -0,0 +1,166 @@
+# 2024 July 30
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# This file verifies that:
+#
+# * blob values may be written to locale=0 tables.
+#
+# * blob values - other than fts5_locale() values - may not be written
+# to locale=0 tables. This is an SQLITE_MISMATCH error
+#
+# * blob values may be returned by queries on the external-content table
+# of a locale=0 table.
+#
+# * blob values not may be returned by queries on the external-content
+# table of a locale=1 table, apart from fts5_locale() blobs. This is an
+# SQLITE_MISMATCH error.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5blob
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+# Test that blobs may be stored in normal locale=0 tables.
+#
+foreach {tn enc} {
+ 1 utf8
+ 2 utf16
+} {
+ reset_db
+ fts5_aux_test_functions db
+
+ execsql "PRAGMA encoding = $enc"
+
+ execsql "
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y);
+ "
+ do_execsql_test 1.$tn.0 {
+ CREATE VIRTUAL TABLE tt USING fts5vocab('t1', 'instance');
+ INSERT INTO t1(rowid, x, y) VALUES(1, 555, X'0000000041424320444546');
+ INSERT INTO t1(rowid, x, y) VALUES(2, 666, X'41424300444546');
+ INSERT INTO t1(rowid, x, y) VALUES(3, 777, 'xyz');
+ }
+
+ do_execsql_test 1.$tn.1 {
+ SELECT rowid, quote(x), quote(y) FROM t1
+ } {
+ 1 555 X'0000000041424320444546'
+ 2 666 X'41424300444546'
+ 3 777 'xyz'
+ }
+
+ do_execsql_test 1.$tn.2 {
+ DELETE FROM t1 WHERE rowid=2;
+ DELETE FROM t1 WHERE rowid=1;
+ }
+
+ do_execsql_test 1.$tn.3 {
+ PRAGMA integrity_check;
+ } {ok}
+}
+
+#--------------------------------------------------------------------------
+# Test that a blob may be stored and retrieved in an unindexed column of
+# a regular table with locale=1.
+#
+reset_db
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(x, y UNINDEXED, locale=1);
+ INSERT INTO t1(rowid, x, y) VALUES(12, 'twelve', X'0000000041424320444546');
+}
+
+do_execsql_test 2.1 {
+ select rowid, x, quote(y) FROM t1
+} {
+ 12 twelve X'0000000041424320444546'
+}
+
+#--------------------------------------------------------------------------
+# Test that blobs may not be written to any type of table with locale=1
+# set. Except, they may be written to UNINDEXED columns.
+#
+reset_db
+do_execsql_test 3.0 {
+ CREATE TABLE t1(a, b);
+
+ CREATE VIRTUAL TABLE x1 USING fts5(a, b, locale=1);
+ CREATE VIRTUAL TABLE x2 USING fts5(a, b, locale=1, content=t2);
+ CREATE VIRTUAL TABLE x3 USING fts5(a, b, locale=1, content=);
+}
+
+do_catchsql_test 3.1 {
+ INSERT INTO x1(rowid, a, b) VALUES(113, 'hello world', X'123456');
+} {0 {}}
+do_catchsql_test 3.2 {
+ INSERT INTO x2(rowid, a, b) VALUES(113, 'hello world', X'123456');
+} {0 {}}
+do_catchsql_test 3.3 {
+ INSERT INTO x3(rowid, a, b) VALUES(113, 'hello world', X'123456');
+} {0 {}}
+
+
+#--------------------------------------------------------------------------
+# Test that fts5_locale() values may not be written to any type of table
+# without locale=1 set. Even to an UNINDEXED column.
+#
+reset_db
+do_execsql_test 3.0 {
+ CREATE TABLE t1(a, b);
+
+ CREATE VIRTUAL TABLE x1 USING fts5(a, b);
+ CREATE VIRTUAL TABLE x2 USING fts5(a, b, content=t2);
+ CREATE VIRTUAL TABLE x3 USING fts5(a, b, content=);
+
+ CREATE VIRTUAL TABLE x4 USING fts5(a, b, c UNINDEXED);
+}
+
+do_catchsql_test 3.1 {
+ INSERT INTO x1(rowid, a, b)
+ VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
+} {1 {fts5_locale() requires locale=1}}
+do_catchsql_test 3.2 {
+ INSERT INTO x2(rowid, a, b)
+ VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
+} {1 {fts5_locale() requires locale=1}}
+do_catchsql_test 3.3 {
+ INSERT INTO x3(rowid, a, b)
+ VALUES(113, 'hello world', fts5_locale('en_AU', 'abc'));
+} {1 {fts5_locale() requires locale=1}}
+do_catchsql_test 3.4 {
+ INSERT INTO x4(rowid, a, b, c)
+ VALUES(113, 'hello world', 'yesno', fts5_locale('en_AU', 'abc'));
+} {1 {fts5_locale() requires locale=1}}
+
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(x);
+}
+
+foreach {tn sql} {
+ 1 { INSERT INTO x1(rowid, x) VALUES(4.5, 'abcd') }
+ 2 { INSERT INTO x1(rowid, x) VALUES('xyz', 'abcd') }
+ 3 { INSERT INTO x1(rowid, x) VALUES(X'001122', 'abcd') }
+} {
+ do_catchsql_test 4.1.$tn $sql {1 {datatype mismatch}}
+}
+
+
+finish_test
+
+
diff --git a/ext/fts5/test/fts5cat.test b/ext/fts5/test/fts5cat.test
index 483f64bfef..71e2abe3ae 100644
--- a/ext/fts5/test/fts5cat.test
+++ b/ext/fts5/test/fts5cat.test
@@ -55,5 +55,22 @@ do_execsql_test 1.5 {
SELECT * FROM t4t
} {สนามกีฬา 1 1}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 "
+ CREATE VIRTUAL TABLE x1 USING fts5(c,
+ tokenize=\"unicode61 categories ' \t'\");
+"
+
+do_catchsql_test 2.1 "
+ CREATE VIRTUAL TABLE x2 USING fts5(c,
+ tokenize=\"unicode61 categories 'N*\t\tMYZ'\");
+" {1 {error in tokenizer constructor}}
+
+do_catchsql_test 2.2 "
+ CREATE VIRTUAL TABLE x2 USING fts5(c,
+ tokenize=\"unicode61 categories 'N*\t\tXYZ'\");
+" {1 {error in tokenizer constructor}}
+
finish_test
diff --git a/ext/fts5/test/fts5circref.test b/ext/fts5/test/fts5circref.test
index ea992195af..8732fa17dd 100644
--- a/ext/fts5/test/fts5circref.test
+++ b/ext/fts5/test/fts5circref.test
@@ -72,7 +72,7 @@ foreach {tn schema sql} {
} {
db_restore_and_reopen
do_execsql_test 1.1.$tn.1 $schema
- do_catchsql_test 1.1.$tn.2 $sql {1 {SQL logic error}}
+ do_catchsql_test 1.1.$tn.2 $sql {1 {database disk image is malformed}}
db close
}
diff --git a/ext/fts5/test/fts5colset.test b/ext/fts5/test/fts5colset.test
index 7243743b51..e5429572c5 100644
--- a/ext/fts5/test/fts5colset.test
+++ b/ext/fts5/test/fts5colset.test
@@ -79,7 +79,7 @@ foreach_detail_mode $::testprefix {
do_catchsql_test 4.1 {
SELECT * FROM t1 WHERE rowid MATCH 'a'
- } {1 {unable to use function MATCH in the requested context}}
+ } {1 {no query solution}}
}
#-------------------------------------------------------------------------
diff --git a/ext/fts5/test/fts5columnsize.test b/ext/fts5/test/fts5columnsize.test
index 2b03d575aa..7af49184b8 100644
--- a/ext/fts5/test/fts5columnsize.test
+++ b/ext/fts5/test/fts5columnsize.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5columnsize
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5config.test b/ext/fts5/test/fts5config.test
index 35894c6bb0..28f3146ea3 100644
--- a/ext/fts5/test/fts5config.test
+++ b/ext/fts5/test/fts5config.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5config
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5content.test b/ext/fts5/test/fts5content.test
index ca2726a902..05b5cc6113 100644
--- a/ext/fts5/test/fts5content.test
+++ b/ext/fts5/test/fts5content.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5content
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -293,4 +293,76 @@ do_catchsql_test 7.2.5 {
SELECT * FROM t1('abc') ORDER BY rank;
} {1 {recursively defined fts5 content table}}
+#---------------------------------------------------------------------------
+# Check that if the content table is a view, and that view contains an
+# error, a reasonable error message is returned if the user tries to
+# read from the view via the fts5 table.
+#
+reset_db
+do_execsql_test 8.1 {
+ CREATE VIEW a1 AS
+ SELECT 1 AS r, text_value(1) AS t
+ UNION ALL
+ SELECT 2 AS r, text_value(2) AS t;
+
+ CREATE VIRTUAL TABLE t1 USING fts5(t, content='a1', content_rowid='r');
+}
+
+foreach {tn sql} {
+ 1 "SELECT * FROM t1"
+ 2 "INSERT INTO t1(t1) VALUES('rebuild')"
+ 3 "SELECT * FROM t1 WHERE rowid=1"
+} {
+ do_catchsql_test 8.2.$tn $sql {1 {no such function: text_value}}
+}
+
+proc text_value {i} {
+ if {$i==1} { return "one" }
+ if {$i==2} { return "two" }
+ return "many"
+}
+db func text_value text_value
+
+do_execsql_test 8.3.1 { SELECT * FROM t1 } {one two}
+do_execsql_test 8.3.2 { INSERT INTO t1(t1) VALUES('rebuild') }
+do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one}
+do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 9.1 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(1, 'one two three');
+ INSERT INTO t1 VALUES(2, 'one two three');
+
+ CREATE VIRTUAL TABLE ft USING fts5(b, content=t1, content_rowid=a);
+ INSERT INTO ft(ft) VALUES('rebuild');
+}
+
+do_execsql_test 9.2 {
+ SELECT rowid, b FROM ft('two');
+} {
+ 1 {one two three}
+ 2 {one two three}
+}
+
+do_execsql_test 9.3 {
+ DELETE FROM t1 WHERE a=2;
+}
+
+do_catchsql_test 9.4 {
+ SELECT rowid FROM ft('two');
+} {0 {1 2}}
+
+do_catchsql_test 9.5 {
+ SELECT * FROM ft('two');
+} {1 {fts5: missing row 2 from content table 'main'.'t1'}}
+
+fts5_aux_test_functions db
+
+do_catchsql_test 9.6 {
+ SELECT rowid, fts5_columntext(ft, 0) FROM ft('two');
+} {1 SQLITE_CORRUPT_VTAB}
+
finish_test
+
diff --git a/ext/fts5/test/fts5contentless.test b/ext/fts5/test/fts5contentless.test
index 48cfd10ffa..991e9888fc 100644
--- a/ext/fts5/test/fts5contentless.test
+++ b/ext/fts5/test/fts5contentless.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -267,4 +267,24 @@ do_execsql_test 8.2 {
SELECT rowid FROM ft('four');
} {}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 9.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(x, content='', contentless_delete=0);
+ INSERT INTO ft VALUES('hello world');
+ INSERT INTO ft VALUES('one two three');
+}
+
+do_catchsql_test 9.1 {
+ INSERT INTO ft(ft, rowid, x) VALUES('delete', 1, 'hello world');
+} {0 {}}
+
+do_catchsql_test 9.2 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', contentless_delete=2);
+} {1 {malformed contentless_delete=... directive}}
+
+do_catchsql_test 9.3 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', contentless_delete=11);
+} {1 {malformed contentless_delete=... directive}}
+
finish_test
diff --git a/ext/fts5/test/fts5contentless2.test b/ext/fts5/test/fts5contentless2.test
index fdd7a60fce..248534bce4 100644
--- a/ext/fts5/test/fts5contentless2.test
+++ b/ext/fts5/test/fts5contentless2.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5contentless3.test b/ext/fts5/test/fts5contentless3.test
index 76119dc592..693840da82 100644
--- a/ext/fts5/test/fts5contentless3.test
+++ b/ext/fts5/test/fts5contentless3.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless3
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5contentless4.test b/ext/fts5/test/fts5contentless4.test
index 702b33a9de..7fdf8c4b01 100644
--- a/ext/fts5/test/fts5contentless4.test
+++ b/ext/fts5/test/fts5contentless4.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless4
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5contentless5.test b/ext/fts5/test/fts5contentless5.test
index a20134d1e7..86d0753286 100644
--- a/ext/fts5/test/fts5contentless5.test
+++ b/ext/fts5/test/fts5contentless5.test
@@ -15,11 +15,12 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless5
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
+unset -nocomplain res
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, content='', contentless_delete=1);
@@ -34,8 +35,8 @@ do_execsql_test 1.01 {
}
# explain_i "UPDATE t1 SET a='a' WHERE t1.rowid=1"
-breakpoint
-explain_i "UPDATE t1 SET a='a' FROM t2 WHERE t1.rowid=1 AND b IS NULL"
+#breakpoint
+#explain_i "UPDATE t1 SET a='a' FROM t2 WHERE t1.rowid=1 AND b IS NULL"
#breakpoint
#explain_i "UPDATE t1 SET a='a' WHERE b IS NULL AND rowid=?"
@@ -55,4 +56,56 @@ foreach {tn up err} {
do_catchsql_test 1.$tn $up $res($err)
}
+#-------------------------------------------------------------------------
+reset_db
+
+proc random {n} { expr {abs(int(rand()*$n))} }
+proc select_one {list} {
+ set n [llength $list]
+ lindex $list [random $n]
+}
+proc vocab {} {
+ list abc def ghi jkl mno pqr stu vwx yza
+}
+proc term {} {
+ select_one [vocab]
+}
+proc document {} {
+ set nTerm [expr [random 3] + 7]
+ set doc ""
+ for {set ii 0} {$ii < $nTerm} {incr ii} {
+ lappend doc [term]
+ }
+ set doc
+}
+db func document document
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a, contentless_delete=1, content='');
+ INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
+}
+
+do_test 2.1 {
+ for {set ii 1} {$ii < 12} {incr ii} {
+ db transaction {
+ for {set jj 0} {$jj < 10} {incr jj} {
+ set doc [document]
+ execsql { INSERT INTO ft VALUES($doc); }
+ }
+ }
+ }
+} {}
+
+do_test 2.2 {
+ foreach r [db eval {SELECT rowid FROM ft}] {
+ execsql { DELETE FROM ft WHERE rowid=$r }
+ }
+} {}
+
+set doc [document]
+do_execsql_test 2.3 {
+ INSERT INTO ft VALUES($doc)
+}
+
+
finish_test
diff --git a/ext/fts5/test/fts5corrupt.test b/ext/fts5/test/fts5corrupt.test
index 9aa84a0ef2..0abd8b86de 100644
--- a/ext/fts5/test/fts5corrupt.test
+++ b/ext/fts5/test/fts5corrupt.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -99,6 +99,27 @@ sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 3.1 {
DELETE FROM t3_content WHERE rowid = 3;
SELECT * FROM t3 WHERE t3 MATCH 'o';
+} {1 {fts5: missing row 3 from content table 'main'.'t3_content'}}
+
+#--------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE t2 USING fts5(x);
+ INSERT INTO t2 VALUES('one two three');
+ INSERT INTO t2 VALUES('four five six');
+ INSERT INTO t2 VALUES('seven eight nine');
+ INSERT INTO t2 VALUES('ten eleven twelve');
+}
+do_execsql_test 4.1 {
+ SELECT hex(block) FROM t2_data WHERE id=1;
+} {040C}
+do_execsql_test 4.2 {
+ UPDATE t2_data SET block = X'0402' WHERE id=1
+}
+breakpoint
+do_catchsql_test 4.3 {
+ DELETE FROM t2 WHERE rowid=3
} {1 {database disk image is malformed}}
finish_test
diff --git a/ext/fts5/test/fts5corrupt2.test b/ext/fts5/test/fts5corrupt2.test
index 06e2e74258..6b4d6d411f 100644
--- a/ext/fts5/test/fts5corrupt2.test
+++ b/ext/fts5/test/fts5corrupt2.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -100,6 +100,7 @@ set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}]
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0
+unset -nocomplain res
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
do_execsql_test 2.$i.1 {
BEGIN;
@@ -152,7 +153,7 @@ foreach {tn hdr} {
execsql BEGIN
set fd [db incrblob main x3_data block $rowid]
- fconfigure $fd -encoding binary -translation binary
+ fconfigure $fd -translation binary
set existing [read $fd [string length $hdr]]
seek $fd 0
puts -nonewline $fd $hdr
@@ -238,7 +239,7 @@ foreach {tn hdr} {
execsql BEGIN
set fd [db incrblob main x5_data block $rowid]
- fconfigure $fd -encoding binary -translation binary
+ fconfigure $fd -translation binary
puts -nonewline $fd $hdr
close $fd
diff --git a/ext/fts5/test/fts5corrupt3.test b/ext/fts5/test/fts5corrupt3.test
index f9a95665c4..437c4842ca 100644
--- a/ext/fts5/test/fts5corrupt3.test
+++ b/ext/fts5/test/fts5corrupt3.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt3
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -680,11 +680,11 @@ do_test 12.0 {
do_catchsql_test 11.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
do_catchsql_test 11.2 {
INSERT INTO t1(t1, rank) VALUES('merge', 500);
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
#
@@ -1040,7 +1040,7 @@ do_test 16.0 {
do_catchsql_test 16.1 {
INSERT INTO t1(t1) VALUES('integrity-check');
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -1126,7 +1126,7 @@ do_test 17.0 {
do_catchsql_test 17.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -1630,7 +1630,7 @@ do_test 20.0 {
do_catchsql_test 20.1 {
SELECT * FROM t1 WHERE t1 MATCH 'abandon';
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
@@ -2100,7 +2100,7 @@ do_test 22.0 {
do_catchsql_test 22.1 {
INSERT INTO t1(t1) VALUES('optimize');
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
#--------------------------------------------------------------------------
reset_db
@@ -3700,7 +3700,7 @@ do_catchsql_test 32.1 {
highlight(t1, 2, '[', ']')
FROM t1('g + h')
WHERE rank MATCH 'bm25(1.0, 1.0)' ORDER BY rank;
-} {1 {vtable constructor failed: t1}}
+} {1 {database disk image is malformed}}
do_catchsql_test 32.2 {
SELECT * FROM t3;
@@ -4267,7 +4267,7 @@ do_test 35.0 {
do_catchsql_test 35.1 {
SELECT * FROM t1 WHERE t1 MATCH 'e*';
-} {1 {database disk image is malformed}}
+} {1 {fts5: missing row 14 from content table 'main'.'t1_content'}}
#-------------------------------------------------------------------------
reset_db
@@ -8958,7 +8958,6 @@ do_catchsql_test 61.2 {
SELECT * FROM t3 ORDER BY rowid;
} {/*malformed database schema*/}
-breakpoint
#-------------------------------------------------------------------------
do_test 62.0 {
sqlite3 db {}
@@ -10768,6 +10767,7 @@ do_catchsql_test 73.1 {
reset_db
do_test 74.0 {
sqlite3 db {}
+ sqlite3_fts5_register_matchinfo db
db deserialize [decode_hexdb {
| size 106496 pagesize 4096 filename x.db
| page 1 offset 0
@@ -14587,14 +14587,19 @@ do_test 74.0 {
| end x.db
}]} {}
-do_catchsql_test 74.1 {
- SELECT rowid, quote(matchinfo(t1,'p�xyb.$..
+| 3072: 00 00 00 00 00 00 00 00 00 00 18 24 05 00 25 0f ...........$..%.
+| 3088: 19 54 48 52 45 41 44 53 41 46 45 3d 30 58 42 49 .THREADSAFE=0XBI
+| 3104: 4e 41 52 59 18 23 05 00 25 0f 19 54 48 52 45 41 NARY.#..%..THREA
+| 3120: 44 53 41 46 45 3d 30 58 4e 4f 43 41 53 45 17 22 DSAFE=0XNOCASE..
+| 3136: 05 00 25 0f 17 54 48 52 45 41 44 53 31 46 45 3d ..%..THREADS1FE=
+| 3152: 30 58 52 64 52 49 4d 1f 21 05 00 33 0f 19 4f 4d 0XRdRIM.!..3..OM
+| 3168: 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 4f IT LOAD EXTENSIO
+| 3184: 4e 58 42 49 4e 41 52 59 1f 20 05 00 33 0f 19 4f NXBINARY. ..3..O
+| 3200: 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 49 MIT LOAD EXTENSI
+| 3216: 4f 4e 58 4e 4f 43 41 53 45 1e 1f 05 00 33 0f 17 ONXNOCASE....3..
+| 3232: 4f 4d 49 54 20 4c 4f 41 44 20 45 58 54 45 4e 53 OMIT LOAD EXTENS
+| 3248: 49 4f 4e 58 52 54 52 49 4d 1f 1e 05 00 33 0f 19 IONXRTRIM....3..
+| 3264: 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 30 MAX MEMORY=50000
+| 3280: 30 30 30 58 42 49 4e 41 52 59 1f 1d 05 00 33 0f 000XBINARY....3.
+| 3296: 19 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 30 .MAX MEMORY=5000
+| 3312: 30 30 30 30 58 4e 4f 43 41 53 45 1e 1c 05 00 33 0000XNOCASE....3
+| 3328: 0f 17 4d 41 58 20 4d 45 4d 4f 52 59 3d 35 30 30 ..MAX MEMORY=500
+| 3344: 30 30 30 30 30 58 52 54 52 49 4d 18 1b 05 00 25 00000XRTRIM....%
+| 3360: 0f 19 45 4e 41 42 4c 45 20 52 54 52 45 45 58 42 ..ENABLE RTREEXB
+| 3376: 49 4e 41 52 59 18 1a 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3392: 4c 45 20 52 54 52 45 45 58 4e 4f 43 41 53 45 17 LE RTREEXNOCASE.
+| 3408: 19 05 00 25 0f 17 45 4e 41 42 4c 45 20 52 54 52 ...%..ENABLE RTR
+| 3424: 45 45 58 52 54 52 49 4d 1a 18 05 00 29 0f 19 45 EEXRTRIM....)..E
+| 3440: 4e 41 42 4b 45 20 4d 45 4d 53 59 53 35 58 42 49 NABKE MEMSYS5XBI
+| 3456: 4e 41 52 59 1a 17 05 00 29 0f 19 45 4e 41 42 4c NARY....)..ENABL
+| 3472: 42 60 2d 45 4d 53 59 53 35 58 4e 4f 43 41 53 45 B`-EMSYS5XNOCASE
+| 3488: 19 16 05 00 29 0f 17 45 4e 41 42 4c 45 20 4d 45 ....)..ENABLE ME
+| 3504: 4d 53 59 53 35 58 52 54 52 49 4d 18 15 05 00 25 MSYS5XRTRIM....%
+| 3520: 0f 19 45 4e 41 42 4c 45 20 4a 53 4f 4e 31 58 42 ..ENABLE JSON1XB
+| 3536: 49 4e 41 52 59 18 14 05 00 25 0f 19 45 4e 41 42 INARY....%..ENAB
+| 3552: 4c 45 20 4a 53 4f 4e 31 58 4e 4f 43 41 53 45 17 LE JSON1XNOCASE.
+| 3568: 13 05 00 25 0f 17 45 4e 41 42 4c 45 20 4a 53 4f ...%..ENABLE JSO
+| 3584: 4e 31 58 52 54 52 49 4d 1a 12 05 00 29 0f 19 45 N1XRTRIM....)..E
+| 3600: 4e 41 42 4c 45 20 47 45 4f 50 4f 4c 59 58 42 49 NABLE GEOPOLYXBI
+| 3616: 4e 41 52 59 1a 11 05 00 39 0f 19 45 4e 41 42 4c NARY....9..ENABL
+| 3632: 45 20 47 45 4f 50 4f 4c 59 58 4e 4f 43 41 53 45 E GEOPOLYXNOCASE
+| 3648: 19 10 05 00 29 0f 17 45 4e 41 42 4c 45 20 47 45 ....)..ENABLE GE
+| 3664: 4f 50 4f 4c 59 58 52 54 52 49 4d 17 0f 05 00 23 OPOLYXRTRIM....#
+| 3680: 0f 19 45 4e 41 42 4c 45 20 46 54 53 35 58 42 49 ..ENABLE FTS5XBI
+| 3696: 4e 41 52 59 17 0e 05 00 23 0f 19 45 4e 41 42 4c NARY....#..ENABL
+| 3712: 45 20 46 54 53 35 58 4e 4f 43 41 53 45 16 0d 05 E FTS5XNOCASE...
+| 3728: 00 23 0f 17 45 4e 41 42 4c 45 20 46 54 53 35 58 .#..ENABLE FTS5X
+| 3744: 52 54 52 49 4d 17 0c 05 00 23 0f 19 45 4e 41 42 RTRIM....#..ENAB
+| 3760: 4c 45 20 46 54 53 34 58 42 49 4e 41 52 59 17 0b LE FTS4XBINARY..
+| 3776: 05 00 23 0f 19 45 4e 41 42 4c 45 20 46 54 53 34 ..#..ENABLE FTS4
+| 3792: 58 4e 4f 43 41 53 45 16 0a 05 00 23 0f 17 45 4e XNOCASE....#..EN
+| 3808: 41 42 4c 45 20 46 54 53 34 58 52 54 52 49 4d 1e ABLE FTS4XRTRIM.
+| 3824: 09 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3840: 54 41 54 20 56 54 41 42 58 42 49 4e 41 52 59 1e TAT VTABXBINARY.
+| 3856: 08 05 00 31 0f 19 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3872: 54 41 54 20 56 54 24 15 48 4e 4f 43 41 53 45 1d TAT VT$.HNOCASE.
+| 3888: 07 05 00 31 0f 17 45 4e 41 42 4c 45 20 44 42 53 ...1..ENABLE DBS
+| 3904: 54 41 54 20 56 54 41 42 58 52 54 52 49 4d 11 06 TAT VTABXRTRIM..
+| 3920: 05 00 17 0f 19 44 45 42 55 47 58 42 49 4e 41 52 .....DEBUGXBINAR
+| 3936: 59 11 05 05 00 17 0f 19 44 45 42 55 47 58 4e 4f Y.......DEBUGXNO
+| 3952: 43 41 53 45 10 04 05 00 17 0f 17 44 45 42 55 47 CASE.......DEBUG
+| 3968: 58 52 54 52 49 4d 27 03 05 00 43 0f 19 43 4f 4d XRTRIM'...C..COM
+| 3984: 50 49 4c 45 52 3d 67 63 63 2d 35 2e 34 2e 30 20 PILER=gcc-5.4.0
+| 4000: 32 30 31 36 30 36 30 39 58 42 49 4e 41 52 59 27 20160609XBINARY'
+| 4016: 02 05 00 43 0f 19 43 4f 4d 50 49 4c 45 52 3c 67 ...C..COMPILER', '') FROM t1('*id');
-} {0 {{}}}
+} {1 {no such cursor: 4}}
do_catchsql_test 1.2.2 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '', '') FROM t1('*id'));
-} {0 {}}
+} {1 {no such cursor: 6}}
do_catchsql_test 1.3.1 {
SELECT highlight(t1, 4, '', '') FROM t1('*reads');
-} {1 {no such cursor: 2}}
+} {1 {no such cursor: 0}}
do_catchsql_test 1.3.2 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '', '') FROM t1('*reads'));
-} {1 {no such cursor: 2}}
+} {1 {no such cursor: 0}}
db close
sqlite3 db test.db
@@ -57,7 +57,12 @@ sqlite3 db test.db
do_catchsql_test 1.3.3 {
SELECT a FROM t1
WHERE rank = (SELECT highlight(t1, 4, '', '') FROM t1('*reads'));
-} {1 {no such cursor: 1}}
+} {1 {no such cursor: 0}}
+
+fts5_aux_test_functions db
+do_catchsql_test 1.3.4 {
+ SELECT fts5_columntext(t1) FROM t1('*reads');
+} {1 {no such cursor: 0}}
#-------------------------------------------------------------------------
reset_db
@@ -91,7 +96,6 @@ do_execsql_test 2.2.1 {
INSERT INTO vt0(c0) VALUES ('xyz');
}
-breakpoint
do_execsql_test 2.2.2 {
ALTER TABLE t0 RENAME TO t1;
}
@@ -500,6 +504,186 @@ do_execsql_test 17.5 {
SELECT c0 FROM t0 WHERE c0 GLOB '*faul*';
} {assertionfaultproblem}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 18.0 {
+ BEGIN;
+ CREATE VIRTUAL TABLE t1 USING fts5(text);
+ ALTER TABLE t1 RENAME TO t2;
+}
+
+do_execsql_test 18.1 {
+ DROP TABLE t2;
+}
+
+do_execsql_test 18.2 {
+ COMMIT;
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 19.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(text);
+ CREATE TABLE t2(text);
+ BEGIN;
+ INSERT INTO t1 VALUES('one');
+ INSERT INTO t1 VALUES('two');
+ INSERT INTO t1 VALUES('three');
+ INSERT INTO t1 VALUES('one');
+ INSERT INTO t1 VALUES('two');
+ INSERT INTO t1 VALUES('three');
+ SAVEPOINT one;
+ INSERT INTO t2 VALUES('one');
+ INSERT INTO t2 VALUES('two');
+ INSERT INTO t2 VALUES('three');
+ ROLLBACK TO one;
+ COMMIT;
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 20.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(a);
+ INSERT INTO x1(rowid, a) VALUES
+ (1, 'a b c d'),
+ (2, 'x b c d'),
+ (3, 'x y z d'),
+ (4, 'a y c x');
+}
+
+do_execsql_test 20.1 {
+ SELECT rowid FROM x1 WHERE x1 MATCH 'a' AND x1 MATCH 'b';
+} {1}
+
+do_execsql_test 20.2 {
+ SELECT rowid FROM x1 WHERE x1 MATCH 'a' AND x1 MATCH 'y';
+} {4}
+
+do_execsql_test 20.3 {
+ SELECT rowid FROM x1 WHERE x1 MATCH 'a' OR x1 MATCH 'y';
+} {1 4 3}
+
+do_execsql_test 20.4 {
+ SELECT rowid FROM x1 WHERE x1 MATCH 'a' OR (x1 MATCH 'y' AND x1 MATCH 'd');
+} {1 4 3}
+
+do_execsql_test 20.5 {
+ SELECT rowid FROM x1 WHERE x1 MATCH 'z' OR (x1 MATCH 'a' AND x1 MATCH 'd');
+} {3 1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 21.0 {
+ CREATE TABLE t1(ii INTEGER, x TEXT, y TEXT);
+ CREATE VIRTUAL TABLE xyz USING fts5(content_rowid=ii, content=t1, x, y);
+ INSERT INTO t1 VALUES(1, 'one', 'i');
+ INSERT INTO t1 VALUES(2, 'two', 'ii');
+ INSERT INTO t1 VALUES(3, 'tree', 'iii');
+ INSERT INTO xyz(xyz) VALUES('rebuild');
+}
+
+do_execsql_test 21.1 {
+ UPDATE xyz SET y='TWO' WHERE rowid=2;
+ UPDATE t1 SET y='TWO' WHERE ii=2;
+}
+
+do_execsql_test 21.2 {
+ PRAGMA integrity_check
+} {ok}
+
+sqlite3_db_config db DEFENSIVE 1
+do_execsql_test 21.3 {
+ CREATE TABLE xyz_notashadow(x, y);
+ DROP TABLE xyz_notashadow;
+}
+sqlite3_db_config db DEFENSIVE 0
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 22.0 {
+ SELECT fts5(NULL);
+} {{}}
+do_execsql_test 22.1 {
+ SELECT count(*) FROM (
+ SELECT fts5_source_id()
+ )
+} {1}
+execsql_pp {
+ SELECT fts5_source_id()
+}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 23.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(x);
+ INSERT INTO x1 VALUES('one + two + three');
+ INSERT INTO x1 VALUES('one + xyz + three');
+ INSERT INTO x1 VALUES('xyz + two + xyz');
+}
+do_execsql_test 23.1 {
+ SELECT rowid FROM x1('one + two + three');
+} {1}
+
+do_execsql_test 23.2 {
+ SELECT rowid FROM x1('^".." AND one');
+} {}
+
+do_execsql_test 23.3 {
+ SELECT rowid FROM x1('abc NEAR ".." NEAR def');
+} {}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 24.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none');
+ INSERT INTO t1(a) VALUES('a');
+}
+
+do_execsql_test 24.2 {
+ SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') ) ORDER BY 1;
+} {-1e-06}
+
+do_execsql_test 24.3 {
+ SELECT rank FROM ( SELECT rank FROM t1('a NOT � NOT def') ) ORDER BY 1;
+} {-1e-06}
+
+do_execsql_test 24.4 {
+ SELECT rank FROM ( SELECT rank FROM t1('a NOT "" NOT def') );
+} {-1e-06}
+
+#-------------------------------------------------------------------------
+reset_db
+fts5_aux_test_functions db
+
+do_execsql_test 25.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, detail='none', content='');
+ INSERT INTO t1(a) VALUES('a b c');
+}
+
+do_execsql_test 25.0 {
+ SELECT fts5_test_poslist(t1) FROM t1('b') ORDER BY rank;
+} {{}}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 26.0 {
+ PRAGMA foreign_keys = ON;
+ CREATE TABLE t1(x INTEGER PRIMARY KEY);
+ CREATE TABLE t2(y INTEGER PRIMARY KEY,
+ z INTEGER REFERENCES t1(x) DEFERRABLE INITIALLY DEFERRED
+ );
+ CREATE VIRTUAL TABLE t3 USING fts5(a, b, content='', tokendata=1);
+}
+
+do_execsql_test 26.1 {
+ BEGIN;
+ INSERT INTO t2 VALUES(1,111);
+ INSERT INTO t3 VALUES(3,3);
+ PRAGMA defer_foreign_keys=ON;
+ DELETE FROM t2 WHERE y+1;
+ COMMIT;
+}
finish_test
diff --git a/ext/fts5/test/fts5near.test b/ext/fts5/test/fts5near.test
index bbe144a898..318a169488 100644
--- a/ext/fts5/test/fts5near.test
+++ b/ext/fts5/test/fts5near.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5near
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5optimize.test b/ext/fts5/test/fts5optimize.test
index e0f0fd7242..610bf439c9 100644
--- a/ext/fts5/test/fts5optimize.test
+++ b/ext/fts5/test/fts5optimize.test
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5optimize2.test b/ext/fts5/test/fts5optimize2.test
index b0b28874c3..57f4e96b99 100644
--- a/ext/fts5/test/fts5optimize2.test
+++ b/ext/fts5/test/fts5optimize2.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5optimize3.test b/ext/fts5/test/fts5optimize3.test
index 7b11b9402d..79e62f9f22 100644
--- a/ext/fts5/test/fts5optimize3.test
+++ b/ext/fts5/test/fts5optimize3.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5origintext.test b/ext/fts5/test/fts5origintext.test
new file mode 100644
index 0000000000..be77cbfca5
--- /dev/null
+++ b/ext/fts5/test/fts5origintext.test
@@ -0,0 +1,357 @@
+# 2014 Jan 08
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+foreach_detail_mode $testprefix {
+foreach {tn insttoken} {
+ 1 0
+ 2 1
+} {
+reset_db
+
+sqlite3_fts5_register_origintext db
+do_execsql_test $tn.1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", detail=%DETAIL%
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+ CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
+}
+
+do_execsql_test $tn.1.1 {
+ INSERT INTO ft VALUES('Hello world');
+}
+
+do_execsql_test $tn.1.2 {
+ INSERT INTO ft(ft) VALUES('integrity-check');
+}
+
+proc b {x} { string map [list "\0" "."] $x }
+db func b b
+
+do_execsql_test $tn.1.3 {
+ select b(term) from vocab;
+} {
+ hello.Hello
+ world
+}
+
+do_execsql_test $tn.1.4 {
+ SELECT rowid FROM ft('Hello');
+} {1}
+
+#-------------------------------------------------------------------------
+reset_db
+
+# Return a random integer between 0 and n-1.
+#
+proc random {n} {
+ expr {abs(int(rand()*$n))}
+}
+
+proc select_one {list} {
+ set n [llength $list]
+ lindex $list [random $n]
+}
+
+proc term {} {
+ set first_letter {
+ a b c d e f g h i j k l m n o p q r s t u v w x y z
+ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+ }
+
+ set term [select_one $first_letter]
+ append term [random 100]
+}
+
+proc document {} {
+ set nTerm [expr [random 5] + 5]
+ set doc ""
+ for {set ii 0} {$ii < $nTerm} {incr ii} {
+ lappend doc [term]
+ }
+ set doc
+}
+db func document document
+
+sqlite3_fts5_register_origintext db
+do_execsql_test $tn.2.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", detail=%DETAIL%
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+ INSERT INTO ft(ft, rank) VALUES('pgsz', 128);
+ CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
+}
+
+do_test $tn.2.1 {
+ for {set ii 0} {$ii < 500} {incr ii} {
+ execsql { INSERT INTO ft VALUES( document() ) }
+ }
+} {}
+
+do_execsql_test $tn.2.2 {
+ INSERT INTO ft(ft) VALUES('integrity-check');
+}
+
+do_execsql_test $tn.2.3 {
+ INSERT INTO ft(ft, rank) VALUES('merge', 16);
+}
+
+do_execsql_test $tn.2.4 {
+ INSERT INTO ft(ft) VALUES('integrity-check');
+}
+
+do_execsql_test $tn.2.5 {
+ INSERT INTO ft(ft) VALUES('optimize');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+sqlite3_fts5_register_origintext db
+do_execsql_test $tn.3.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", detail=%DETAIL%
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+ CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
+
+ INSERT INTO ft(rowid, x) VALUES(1, 'hello');
+ INSERT INTO ft(rowid, x) VALUES(2, 'Hello');
+ INSERT INTO ft(rowid, x) VALUES(3, 'HELLO');
+}
+
+#proc b {x} { string map [list "\0" "."] $x }
+#db func b b
+#execsql_pp { SELECT b(term) FROM vocab }
+
+do_execsql_test $tn.3.1.1 { SELECT rowid FROM ft('hello') } 1
+do_execsql_test $tn.3.1.2 { SELECT rowid FROM ft('Hello') } 2
+do_execsql_test $tn.3.1.3 { SELECT rowid FROM ft('HELLO') } 3
+
+do_execsql_test $tn.3.2 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(x,
+ tokenize="origintext unicode61",
+ tokendata=1,
+ detail=%DETAIL%
+ );
+ INSERT INTO ft2(ft2, rank) VALUES('insttoken', $insttoken);
+ CREATE VIRTUAL TABLE vocab2 USING fts5vocab(ft2, instance);
+
+ INSERT INTO ft2(rowid, x) VALUES(1, 'hello');
+ INSERT INTO ft2(rowid, x) VALUES(2, 'Hello');
+ INSERT INTO ft2(rowid, x) VALUES(3, 'HELLO');
+
+ INSERT INTO ft2(rowid, x) VALUES(10, 'helloooo');
+}
+
+#proc b {x} { string map [list "\0" "."] $x }
+#db func b b
+#execsql_pp { SELECT b(term) FROM vocab }
+
+do_execsql_test $tn.3.3.1 { SELECT rowid FROM ft2('hello') } {1 2 3}
+do_execsql_test $tn.3.3.2 { SELECT rowid FROM ft2('Hello') } {1 2 3}
+do_execsql_test $tn.3.3.3 { SELECT rowid FROM ft2('HELLO') } {1 2 3}
+
+do_execsql_test $tn.3.3.4 { SELECT rowid FROM ft2('hello*') } {1 2 3 10}
+
+do_execsql_test $tn.3.3.5.1 { SELECT rowid FROM ft2('HELLO') ORDER BY rowid DESC} {
+ 3 2 1
+}
+do_execsql_test $tn.3.3.5.2 { SELECT rowid FROM ft2('HELLO') ORDER BY +rowid DESC} {
+ 3 2 1
+}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+sqlite3_fts5_register_origintext db
+proc querytoken {cmd iPhrase iToken} {
+ set txt [$cmd xQueryToken $iPhrase $iToken]
+ string map [list "\0" "."] $txt
+}
+sqlite3_fts5_create_function db querytoken querytoken
+
+do_execsql_test $tn.4.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+ INSERT INTO ft VALUES('one two three four');
+}
+
+do_execsql_test $tn.4.1 {
+ SELECT rowid, querytoken(ft, 0, 0) FROM ft('TwO')
+} {1 two.TwO}
+do_execsql_test $tn.4.2 {
+ SELECT rowid, querytoken(ft, 0, 0) FROM ft('one TWO ThreE')
+} {1 one}
+do_execsql_test $tn.4.3 {
+ SELECT rowid, querytoken(ft, 1, 0) FROM ft('one TWO ThreE')
+} {1 two.TWO}
+
+if {"%DETAIL%"=="full"} {
+ # Phrase queries are only supported for detail=full.
+ #
+ do_execsql_test $tn.4.4 {
+ SELECT rowid, querytoken(ft, 0, 2) FROM ft('"one TWO ThreE"')
+ } {1 three.ThreE}
+ do_catchsql_test $tn.4.5 {
+ SELECT rowid, querytoken(ft, 0, 3) FROM ft('"one TWO ThreE"')
+ } {1 SQLITE_RANGE}
+ do_catchsql_test $tn.4.6 {
+ SELECT rowid, querytoken(ft, 1, 0) FROM ft('"one TWO ThreE"')
+ } {1 SQLITE_RANGE}
+ do_catchsql_test $tn.4.7 {
+ SELECT rowid, querytoken(ft, -1, 0) FROM ft('"one TWO ThreE"')
+ } {1 SQLITE_RANGE}
+}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+sqlite3_fts5_register_origintext db
+proc insttoken {cmd iIdx iToken} {
+ set txt [$cmd xInstToken $iIdx $iToken]
+ string map [list "\0" "."] $txt
+}
+sqlite3_fts5_create_function db insttoken insttoken
+fts5_aux_test_functions db
+
+do_execsql_test $tn.5.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize='origintext unicode61', tokendata=1, detail=%DETAIL%
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+ INSERT INTO ft VALUES('one ONE One oNe oNE one');
+}
+
+do_execsql_test $tn.5.1 {
+ SELECT insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0),
+ insttoken(ft, 3, 0),
+ insttoken(ft, 4, 0),
+ insttoken(ft, 5, 0)
+ FROM ft('one');
+} {
+ one one.ONE one.One one.oNe one.oNE one
+}
+
+do_execsql_test $tn.5.2 {
+ SELECT insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0),
+ insttoken(ft, 3, 0),
+ insttoken(ft, 4, 0),
+ insttoken(ft, 5, 0)
+ FROM ft('on*');
+} {
+ one one.ONE one.One one.oNe one.oNE one
+}
+
+do_execsql_test $tn.5.3 {
+ SELECT insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0),
+ insttoken(ft, 3, 0),
+ insttoken(ft, 4, 0),
+ insttoken(ft, 5, 0)
+ FROM ft(fts5_insttoken('on*'));
+} {
+ one one.ONE one.One one.oNe one.oNE one
+}
+
+do_execsql_test $tn.5.4 {
+ SELECT insttoken(ft, 1, 0) FROM ft('one');
+} {
+ one.ONE
+}
+
+do_execsql_test $tn.5.5 {
+ SELECT fts5_test_poslist(ft) FROM ft('one');
+} {
+ {0.0.0 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5}
+}
+
+#-------------------------------------------------------------------------
+# Test the xInstToken() API with:
+#
+# * a non tokendata=1 table.
+# * prefix queries.
+#
+reset_db
+sqlite3_fts5_register_origintext db
+do_execsql_test $tn.6.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, y, tokenize='origintext unicode61', detail=%DETAIL%, tokendata=0
+ );
+ INSERT INTO ft(ft, rank) VALUES('insttoken', $insttoken);
+
+ INSERT INTO ft VALUES('One Two', 'Three two');
+ INSERT INTO ft VALUES('three Three', 'one One');
+}
+proc tokens {cmd} {
+ set ret [list]
+ for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
+ set txt [$cmd xInstToken $iTok 0]
+ set txt [string map [list "\0" "."] $txt]
+ lappend ret $txt
+ }
+ set ret
+}
+sqlite3_fts5_create_function db tokens tokens
+
+do_execsql_test $tn.6.1 {
+ SELECT rowid, tokens(ft) FROM ft('One');
+} {1 one.One 2 one.One}
+
+do_execsql_test $tn.6.2 {
+ SELECT rowid, tokens(ft) FROM ft('on*');
+} {1 one.One 2 {one one.One}}
+
+do_execsql_test $tn.6.3 {
+ SELECT rowid, tokens(ft) FROM ft('Three*');
+} {1 three.Three 2 three.Three}
+
+fts5_aux_test_functions db
+do_catchsql_test $tn.6.4 {
+ SELECT fts5_test_insttoken(ft, -1, 0) FROM ft('one');
+} {1 SQLITE_RANGE}
+
+do_catchsql_test $tn.6.5 {
+ SELECT fts5_test_insttoken(ft, 1, 0) FROM ft('one');
+} {1 SQLITE_RANGE}
+
+do_catchsql_test $tn.6.6 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(x, tokendata=2);
+} {1 {malformed tokendata=... directive}}
+do_catchsql_test $tn.6.7 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(x, content='', tokendata=11);
+} {1 {malformed tokendata=... directive}}
+
+}
+}
+
+finish_test
+
diff --git a/ext/fts5/test/fts5origintext2.test b/ext/fts5/test/fts5origintext2.test
new file mode 100644
index 0000000000..a8c7172344
--- /dev/null
+++ b/ext/fts5/test/fts5origintext2.test
@@ -0,0 +1,146 @@
+# 2014 Jan 08
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext2
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+sqlite3_fts5_register_origintext db
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", tokendata=1
+ );
+}
+
+do_execsql_test 1.1 {
+ BEGIN;
+ INSERT INTO ft VALUES('Hello');
+ INSERT INTO ft VALUES('hello');
+ INSERT INTO ft VALUES('HELLO');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('World');
+ INSERT INTO ft VALUES('world');
+ INSERT INTO ft VALUES('WORLD');
+ COMMIT;
+}
+
+do_execsql_test 1.2 { SELECT rowid FROM ft('hello'); } {1 2 3}
+do_execsql_test 1.3 { SELECT rowid FROM ft('today'); } {4 5 6}
+do_execsql_test 1.4 { SELECT rowid FROM ft('world'); } {7 8 9}
+
+do_execsql_test 1.5 {
+ SELECT count(*) FROM ft_data
+} 3
+
+do_execsql_test 1.6 {
+ DELETE FROM ft;
+ INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
+ BEGIN;
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100
+ )
+ INSERT INTO ft SELECT 'Hello Hello Hello Hello Hello Hello Hello' FROM s;
+ INSERT INTO ft VALUES ('hELLO hELLO hELLO');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('today today today today today today today');
+ INSERT INTO ft VALUES('World World World World World World World');
+ INSERT INTO ft VALUES('world world world world world world world');
+ INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
+ INSERT INTO ft VALUES('World World World World World World World');
+ INSERT INTO ft VALUES('world world world world world world world');
+ INSERT INTO ft VALUES('WORLD WORLD WORLD WORLD WORLD WORLD WORLD');
+ COMMIT;
+}
+
+do_execsql_test 1.7 {
+ SELECT count(*) FROM ft_data;
+} 23
+
+do_execsql_test 1.8 { SELECT rowid FROM ft('hello') WHERE rowid>100; } {101}
+
+do_execsql_test 1.9 {
+ DELETE FROM ft;
+ INSERT INTO ft(ft) VALUES('optimize');
+ SELECT count(*) FROM ft_data;
+} {2}
+do_execsql_test 1.10 {
+ BEGIN;
+ INSERT INTO ft VALUES('Hello');
+ INSERT INTO ft VALUES('hello');
+ INSERT INTO ft VALUES('HELLO');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('today');
+ INSERT INTO ft VALUES('World');
+ INSERT INTO ft VALUES('world');
+ INSERT INTO ft VALUES('WORLD');
+}
+
+do_execsql_test 1.11 { SELECT rowid FROM ft('hello'); } {1 2 3}
+do_execsql_test 1.12 { SELECT rowid FROM ft('today'); } {4 5 6}
+do_execsql_test 1.13 { SELECT rowid FROM ft('world'); } {7 8 9}
+do_execsql_test 1.14 { SELECT rowid FROM ft('hello') ORDER BY rank; } {1 2 3}
+
+#------------------------------------------------------------------------
+reset_db
+sqlite3_fts5_register_origintext db
+proc tokens {cmd} {
+ set ret [list]
+ for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
+ set txt [$cmd xInstToken $iTok 0]
+ set txt [string map [list "\0" "."] $txt]
+ lappend ret $txt
+ }
+ set ret
+}
+sqlite3_fts5_create_function db tokens tokens
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(
+ v, tokenize="origintext unicode61", tokendata=1, detail=none
+ );
+
+ INSERT INTO x1 VALUES('xxx Xxx XXX yyy YYY yyy');
+ INSERT INTO x1 VALUES('xxx yyy xxx yyy yyy yyy');
+}
+
+do_execsql_test 2.1 {
+ SELECT tokens(x1) FROM x1('xxx');
+} {
+ {xxx xxx.Xxx xxx.XXX} {xxx xxx}
+}
+
+do_execsql_test 2.2 {
+ UPDATE x1_content SET c0 = 'xxx xxX xxx yyy yyy yyy' WHERE id=1;
+}
+
+do_execsql_test 2.3 {
+ SELECT tokens(x1) FROM x1('xxx');
+} {
+ {xxx {} xxx} {xxx xxx}
+}
+
+finish_test
+
diff --git a/ext/fts5/test/fts5origintext3.test b/ext/fts5/test/fts5origintext3.test
new file mode 100644
index 0000000000..351ab1f617
--- /dev/null
+++ b/ext/fts5/test/fts5origintext3.test
@@ -0,0 +1,141 @@
+# 2023 November 22
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext3
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+foreach_detail_mode $testprefix {
+ foreach {tn insttoken} {
+ 1 0
+ 2 1
+ } {
+
+ reset_db
+
+ sqlite3_fts5_register_origintext db
+ fts5_aux_test_functions db
+ proc insttoken {cmd iIdx iToken} {
+ set txt [$cmd xInstToken $iIdx $iToken]
+ string map [list "\0" "."] $txt
+ }
+ sqlite3_fts5_create_function db insttoken insttoken
+
+ do_execsql_test $tn.1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
+ );
+ }
+
+ do_execsql_test $tn.1.0.1 {
+ INSERT INTO ft(ft, rank) VALUES('insttoken', 1);
+ }
+
+ do_execsql_test $tn.1.1 {
+ INSERT INTO ft VALUES('Hello world HELLO WORLD hello');
+ }
+
+ do_execsql_test $tn.1.2 {
+ SELECT fts5_test_poslist(ft) FROM ft('hello');
+ } {{0.0.0 0.0.2 0.0.4}}
+
+ do_execsql_test $tn.1.3 {
+ SELECT
+ insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0)
+ FROM ft('hello');
+ } {hello.Hello hello.HELLO hello}
+
+ do_execsql_test $tn.1.3.1 {
+ SELECT
+ insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0)
+ FROM ft('hel*');
+ } {hello.Hello hello.HELLO hello}
+
+ do_execsql_test $tn.1.4 {
+ SELECT
+ insttoken(ft, 0, 0),
+ insttoken(ft, 1, 0),
+ insttoken(ft, 2, 0)
+ FROM ft('hello') ORDER BY rank;
+ } {hello.Hello hello.HELLO hello}
+
+ do_execsql_test $tn.1.5 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(
+ x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
+ );
+ INSERT INTO ft2(rowid, x) VALUES(1, 'ONE one two three ONE');
+ INSERT INTO ft2(rowid, x) VALUES(2, 'TWO one two three TWO');
+ INSERT INTO ft2(rowid, x) VALUES(3, 'THREE one two three THREE');
+ }
+
+ do_execsql_test $tn.1.6 {
+ SELECT insttoken(ft2, 0, 0), rowid FROM ft2('three') ORDER BY rank;
+ } {three.THREE 3 three 1 three 2}
+
+ do_execsql_test $tn.1.7 {
+ INSERT INTO ft2(rowid, x) VALUES(10, 'aaa bbb BBB');
+ INSERT INTO ft2(rowid, x) VALUES(12, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(13, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(14, 'bbb BBB bbb');
+ INSERT INTO ft2(rowid, x) VALUES(15, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(16, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(17, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(18, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(19, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(20, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(21, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(22, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(23, 'bbb bbb bbb');
+ INSERT INTO ft2(rowid, x) VALUES(24, 'aaa bbb BBB');
+ }
+
+ do_execsql_test $tn.1.8 { SELECT rowid FROM ft2('aaa AND bbb'); } {10 24}
+ do_execsql_test $tn.1.9 { SELECT rowid FROM ft2('bbb AND aaa'); } {10 24}
+
+ do_execsql_test $tn.2.0 {
+ CREATE VIRTUAL TABLE ft3 USING fts5(
+ x, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
+ prefix=2
+ );
+ }
+ do_execsql_test $tn.2.1 {
+ INSERT INTO ft3(rowid, x) VALUES(1, 'one');
+ INSERT INTO ft3(rowid, x) VALUES(2, 'ONE');
+ INSERT INTO ft3(rowid, x) VALUES(3, 'ONT');
+ INSERT INTO ft3(rowid, x) VALUES(4, 'on');
+ INSERT INTO ft3(rowid, x) VALUES(5, 'On');
+ }
+
+ do_execsql_test $tn.2.2 {
+ SELECT rowid FROM ft3('on*');
+ } {1 2 3 4 5}
+
+ do_execsql_test $tn.2.3 {
+ SELECT rowid, insttoken(ft3, 0, 0) FROM ft3('on*');
+ } {1 one 2 one.ONE 3 ont.ONT 4 on 5 on.On}
+
+ }
+}
+
+finish_test
+
diff --git a/ext/fts5/test/fts5origintext4.test b/ext/fts5/test/fts5origintext4.test
new file mode 100644
index 0000000000..3b907ba2cc
--- /dev/null
+++ b/ext/fts5/test/fts5origintext4.test
@@ -0,0 +1,80 @@
+# 2023 November 22
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext4
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+# The tests below verify that a doclist-index is used to limit the number
+# of pages loaded into the cache. It does this by querying sqlite3_db_status()
+# for the amount of memory used by the pager cache.
+#
+# memsubsys1 effectively limits the page-cache to 24 pages. Which masks
+# the effect tested by the tests in this file. And "mmap" prevents the
+# cache from being used, also preventing these tests from working.
+#
+if {[permutation]=="memsubsys1" || [permutation]=="mmap"} {
+ finish_test
+ return
+}
+
+sqlite3_fts5_register_origintext db
+do_execsql_test 1.0 {
+ PRAGMA page_size = 4096;
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", tokendata=1
+ );
+}
+
+do_execsql_test 1.1 {
+ BEGIN;
+ INSERT INTO ft SELECT 'the first thing';
+
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<90000
+ )
+ INSERT INTO ft SELECT 'The second thing' FROM s;
+
+ INSERT INTO ft SELECT 'the first thing';
+ COMMIT;
+ INSERT INTO ft(ft) VALUES('optimize');
+}
+
+foreach {tn sql expr} {
+ 1 { SELECT rowid FROM ft('the') } {$mem > 250000}
+ 2 { SELECT rowid FROM ft('first') } {$mem < 50000}
+ 3 { SELECT rowid FROM ft('the first') } {$mem < 50000}
+} {
+ db close
+ sqlite3 db test.db
+ sqlite3_fts5_register_origintext db
+
+ execsql $sql
+ do_test 1.2.$tn {
+ set mem [lindex [sqlite3_db_status db CACHE_USED 0] 1]
+ expr $expr
+ } 1
+}
+
+proc b {x} { string map [list "\0" "."] $x }
+db func b b
+# execsql_pp { SELECT segid, b(term), pgno from ft_idx }
+
+finish_test
+
diff --git a/ext/fts5/test/fts5origintext5.test b/ext/fts5/test/fts5origintext5.test
new file mode 100644
index 0000000000..848cc15b5c
--- /dev/null
+++ b/ext/fts5/test/fts5origintext5.test
@@ -0,0 +1,273 @@
+# 2023 Dec 04
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests for tables that use both tokendata=1 and contentless_delete=1.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+# Return a random integer between 0 and n-1.
+#
+proc random {n} { expr {abs(int(rand()*$n))} }
+
+# Select an element of the list passed as the only argument at random and
+# return it.
+#
+proc select_one {list} {
+ set n [llength $list]
+ lindex $list [random $n]
+}
+
+# Given a term that consists entirely of alphabet characters, return all
+# permutations of the term using upper and lower case characters. e.g.
+#
+# "abc" -> {CBA cBA CbA cbA CBa cBa Cba cba}
+#
+proc casify {term {lRet {{}}}} {
+ if {$term==""} { return $lRet }
+ set t [string range $term 1 end]
+ set f1 [string toupper [string range $term 0 0]]
+ set f2 [string tolower [string range $term 0 0]]
+ set ret [list]
+ foreach x $lRet {
+ lappend ret "$x$f1"
+ lappend ret "$x$f2"
+ }
+ return [casify $t $ret]
+}
+
+proc vocab {} {
+ list abc def ghi jkl mno pqr stu vwx yza
+}
+
+# Return a random 3 letter term.
+#
+proc term {} {
+ if {[info exists ::expanded_vocab]==0} {
+ foreach v [vocab] { lappend ::expanded_vocab {*}[casify $v] }
+ }
+
+ select_one $::expanded_vocab
+}
+
+# Return a document - between 3 and 10 terms.
+#
+proc document {} {
+ set nTerm [expr [random 3] + 7]
+ set doc ""
+ for {set ii 0} {$ii < $nTerm} {incr ii} {
+ lappend doc [term]
+ }
+ set doc
+}
+db func document document
+
+#-------------------------------------------------------------------------
+
+expr srand(6)
+
+set NDOC 200
+set NLOOP 50
+
+sqlite3_fts5_register_origintext db
+
+proc tokens {cmd} {
+ set ret [list]
+ for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
+ set txt [$cmd xInstToken $iTok 0]
+ set txt [string map [list "\0" "."] $txt]
+ lappend ret $txt
+ }
+ set ret
+}
+sqlite3_fts5_create_function db tokens tokens
+
+proc rankfunc {cmd} {
+ $cmd xRowid
+}
+sqlite3_fts5_create_function db rankfunc rankfunc
+
+proc ctrl_tokens {term args} {
+ set ret [list]
+ set term [string tolower $term]
+ foreach doc $args {
+ foreach a $doc {
+ if {[string tolower $a]==$term} {
+ if {$a==$term} {
+ lappend ret $a
+ } else {
+ lappend ret [string tolower $a].$a
+ }
+ }
+ }
+ }
+ set ret
+}
+db func ctrl_tokens ctrl_tokens
+
+proc do_all_vocab_test {tn} {
+ foreach ::v [concat [vocab] nnn] {
+ set answer [execsql {
+ SELECT id, ctrl_tokens($::v, x) FROM ctrl WHERE x LIKE '%' || $::v || '%'
+ }]
+ do_execsql_test $tn.$::v.1 {
+ SELECT rowid, tokens(ft) FROM ft($::v)
+ } $answer
+ do_execsql_test $tn.$::v.2 {
+ SELECT rowid, tokens(ft) FROM ft($::v) ORDER BY rank
+ } $answer
+ }
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, tokenize="origintext unicode61", content=, contentless_delete=1,
+ tokendata=1
+ );
+
+ CREATE TABLE ctrl(id INTEGER PRIMARY KEY, x TEXT);
+ INSERT INTO ft(ft, rank) VALUES('pgsz', 64);
+ INSERT INTO ft(ft, rank) VALUES('rank', 'rankfunc()');
+}
+do_test 1.1 {
+ for {set ii 0} {$ii < $NDOC} {incr ii} {
+ set doc [document]
+ execsql {
+ INSERT INTO ft(rowid, x) VALUES($ii, $doc);
+ INSERT INTO ctrl(id, x) VALUES($ii, $doc);
+ }
+ }
+} {}
+
+#execsql_pp { SELECT * FROM ctrl }
+#execsql_pp { SELECT * FROM ft }
+#fts5_aux_test_functions db
+#execsql_pp { SELECT rowid, tokens(ft), fts5_test_poslist(ft) FROM ft('ghi'); }
+
+do_all_vocab_test 1.2
+
+for {set ii 0} {$ii < $NLOOP} {incr ii} {
+ set lRowid [execsql { SELECT id FROM ctrl WHERE random() % 2 }]
+ foreach r $lRowid {
+ execsql { DELETE FROM ft WHERE rowid = $r }
+ execsql { DELETE FROM ctrl WHERE rowid = $r }
+
+ set doc [document]
+ execsql { INSERT INTO ft(rowid, x) VALUES($r, $doc) }
+ execsql { INSERT INTO ctrl(id, x) VALUES($r, $doc) }
+ }
+ do_all_vocab_test 1.3.$ii
+}
+
+#-------------------------------------------------------------------------
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(
+ x, y, tokenize="origintext unicode61", content=, contentless_delete=1,
+ tokendata=1
+ );
+
+ CREATE TABLE ctrl2(id INTEGER PRIMARY KEY, x TEXT, y TEXT);
+ INSERT INTO ft2(ft2, rank) VALUES('pgsz', 64);
+ INSERT INTO ft2(ft2, rank) VALUES('rank', 'rankfunc()');
+}
+do_test 2.1 {
+ for {set ii 0} {$ii < $NDOC} {incr ii} {
+ set doc1 [document]
+ set doc2 [document]
+ execsql {
+ INSERT INTO ft2(rowid, x, y) VALUES($ii, $doc, $doc2);
+ INSERT INTO ctrl2(id, x, y) VALUES($ii, $doc, $doc2);
+ }
+ }
+} {}
+
+proc do_all_vocab_test2 {tn} {
+ foreach ::v [vocab] {
+ set answer [execsql {
+ SELECT id, ctrl_tokens($::v, x, y) FROM ctrl2
+ WHERE x LIKE '%' || $::v || '%' OR y LIKE '%' || $::v || '%';
+ }]
+ do_execsql_test $tn.$::v.1 {
+ SELECT rowid, tokens(ft2) FROM ft2($::v)
+ } $answer
+ do_execsql_test $tn.$::v.2 {
+ SELECT rowid, tokens(ft2) FROM ft2($::v) ORDER BY rank
+ } $answer
+ }
+}
+
+do_all_vocab_test2 2.2
+
+for {set ii 0} {$ii < $NLOOP} {incr ii} {
+ set lRowid [execsql { SELECT id FROM ctrl2 WHERE random() % 2 }]
+ foreach r $lRowid {
+ execsql { DELETE FROM ft2 WHERE rowid = $r }
+ execsql { DELETE FROM ctrl2 WHERE rowid = $r }
+
+ set doc1 [document]
+ set doc2 [document]
+ execsql { INSERT INTO ft2(rowid, x, y) VALUES($r, $doc, $doc1) }
+ execsql { INSERT INTO ctrl2(id, x, y) VALUES($r, $doc, $doc2) }
+ }
+ do_all_vocab_test 2.3.$ii
+}
+
+#-------------------------------------------------------------------------
+
+unset -nocomplain ::expanded_vocab
+proc vocab {} {
+ list abcde fghij klmno
+}
+
+proc do_all_vocab_test3 {tn} {
+ foreach ::v [concat [vocab] nnn] {
+ set answer [execsql {
+ SELECT rowid, ctrl_tokens($::v, w) FROM ctrl3 WHERE w LIKE '%' || $::v || '%'
+ }]
+ do_execsql_test $tn.$::v.1 {
+ SELECT rowid, tokens(ft3) FROM ft3($::v)
+ } $answer
+ do_execsql_test $tn.$::v.2 {
+ SELECT rowid, tokens(ft3) FROM ft3($::v) ORDER BY rank
+ } $answer
+ }
+}
+
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE ft3 USING fts5(
+ w, tokenize="origintext unicode61", content=, contentless_delete=1,
+ tokendata=1
+ );
+ INSERT INTO ft3(ft3, rank) VALUES('rank', 'rankfunc()');
+ CREATE TABLE ctrl3(w);
+}
+
+do_execsql_test 3.1 {
+ WITH s(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<2
+ )
+ INSERT INTO ctrl3 SELECT document() FROM s;
+ INSERT INTO ft3(rowid, w) SELECT rowid, w FROM ctrl3;
+}
+
+do_all_vocab_test3 3.2
+
+
+finish_test
+
diff --git a/ext/fts5/test/fts5origintext6.test b/ext/fts5/test/fts5origintext6.test
new file mode 100644
index 0000000000..7b27e310b9
--- /dev/null
+++ b/ext/fts5/test/fts5origintext6.test
@@ -0,0 +1,209 @@
+# 2014 Jan 08
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5origintext6
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+proc insert_data {tbl} {
+ db eval "
+ INSERT INTO $tbl (rowid, x, y) VALUES
+ (1, 'ChH BDd HhG efc BjJ BGi GBG FdD','ciJ AFf ADf fBJ fhC GFI JEH fcA'),
+ (2, 'deg AIG Fie jII cCd Hbf igF fEE','GeA Ija gJg EDc HFi DDI dCf aDd'),
+ (3, 'IJC hga deC Jfa Aeg hfh CcH dfb','ajD hgC Jaf IfH CHe jIG AjD adF'),
+ (4, 'FiH GJH IDA AiG bBc CGG Eih bIH','hHg JaH aii IHE Ggd gcH gji CGc'),
+ (5, 'ceg CAd jFI GAB BGg EeC IdH acG','bBC eIG ifH eDE Adj bjb GCj ebA'),
+ (6, 'Eac Fbh aFF Eea jeG EIj HCc JJH','hbd giE Gfe eiI dEF abE cJf cAb'),
+ (7, 'dic hAc jEC AiG FEF jHc HiD HBI','aEd ebE Gfi AJG EBA faj GiG jjE'),
+ (8, 'Fca iEe EgE jjJ gce ijf EGc EBi','gaI dhH bFg CFc HeC CjI Jfg ccH'),
+ (9, 'cfd iaa HCf iHJ HjG ffh ABb ibi','CfG bia Dai eii Ejg Jeg fCg hDb'),
+ (10, 'Jjf hJC IID HJj bGB EbJ cgg eBj','jci jhi JAF jIg Bei Bcd cAC AJd'),
+ (11, 'egG Cdi bFf fEB hfH jDH jia Efd','FAd eCg fAi aiC baC eJG acF iGE'),
+ (12, 'Ada Gde CJI ADG gJA Cbb ccF iAB','eAE ajC FBB ccd Jgh fJg ieg hGE'),
+ (13, 'gBb fDG Jdd HdD fiJ Bed Cig iGg','heC FeI iaj gdg ebB giC HaD FIe'),
+ (14, 'FiI iDd Ffe igI bgB EJf FHG hDF','cjC AeI abf Fah cbJ ffH jEb aib'),
+ (15, 'jaF hBI jIH Gdh FEc Fij hgj jFh','dGA ADH feh AAI AfJ DbC gBi hGH'),
+ (16, 'gjH BGg iGj aFE CAH edI idf HEH','hIf DDg fjB hGi cHF BCH FjG Bgd'),
+ (17, 'iaI JGH hji gcj Dda eeG jDd CBi','cHg jeh caG gIc feF ihG hgJ Abj'),
+ (18, 'jHI iDB eFf AiH EFB CDb IAj GbC','Ghe dEI gdI jai gib dAG BIa djb'),
+ (19, 'abI fHG Ccf aAc FDa fiC agF bdB','afi hde IgE bGF cfg DHD diE aca'),
+ (20, 'IFh eDJ jfh cDg dde JGJ GAf fIJ','IBa EfH faE aeI FIF baJ FGj EIH'),
+ (21, 'Dee bFC bBA dEI CEj aJI ghA dCH','hBA ddA HJh dfj egI Dij dFE bGE'),
+ (22, 'JFE BCj FgA afc Jda FGD iHJ HDh','eAI jHe BHD Gah bbD Bgj gbh eGB'),
+ (23, 'edE CJE FjG aFI edA Cea FId iFe','ABG jcA ddj EEc Dcg hAI agA biA'),
+ (24, 'AgE cfc eef cGh aFB DcH efJ hcH','eGF HaB diG fgi bdc iGJ FGJ fFB'),
+ (25, 'aCa AgI GhC DDI hGJ Hgc Gcg bbG','iID Fga jHa jIj idj DFD bAC AFJ'),
+ (26, 'gjC JGh Fge faa eCA iGG gHE Gai','bDi hFE BbI DHD Adb Fgi hCa Hij'),
+ (27, 'Eji jEI jhF DFC afH cDh AGc dHA','IDe GcA ChF DIb Bif HfH agD DGh'),
+ (28, 'gDD AEE Dfg ICf Cbi JdE jgH eEi','eEb dBG FDE jgf cAI FaJ jaA cDd'),
+ (29, 'cbe Gec hgB Egi bca dHg bAJ jBf','EFB DgD GJc fDb EeE bBA GFC Hbe'),
+ (30, 'Adc eHB afI hDc Bhh baE hcJ BBd','JAH deg bcF Dab Bgj Gbb JHi FIB'),
+ (31, 'agF dIj AJJ Hfg cCG hED Igc fHC','JEf eia dHf Ggc Agj geD bEE Gei'),
+ (32, 'DAd cCe cbJ FjG gJe gba dJA GCf','eAf hFc bGE ABI hHA IcE abF CCE'),
+ (33, 'fFh jJe DhJ cDJ EBi AfD eFI IhG','fEG GCc Bjd EFF ggg CFe EHd ciB'),
+ (34, 'Ejb BjI eAF HaD eEJ FaG Eda AHC','Iah hgD EJG fdD cIE Daj IFf eJh'),
+ (35, 'aHG eCe FjA djJ dAJ jiJ IaE GGB','Acg iEF JfB FIC Eei ggj dic Iii'),
+ (36, 'Fdb EDF GaF JjB ehH IgC hgi DCG','cag DHI Fah hAJ bbh egG Hia hgJ'),
+ (37, 'HGg icC JEC AFJ Ddh dhi hfC Ich','fEg bED Bff hCJ EiA cIf bfG cGA'),
+ (38, 'aEJ jGI BCi FaA ebA BHj cIJ GcC','dCH ADd bGB cFE AgF geD cbG jIc'),
+ (39, 'JFB bBi heA BFA hgB Ahj EIE CgI','EIJ JFG FJE GeA Hdg HeH ACh GiA'),
+ (40, 'agB DDC CED igC Dfc DhI eiC fHi','dAB dcg iJF cej Fcc cAc AfB Fdd'),
+ (41, 'BdF DHj Ege hcG DEd eFa dCf gBb','FBG ChB cej iGd Hbh fCc Ibe Abh'),
+ (42, 'Bgc DjI cbC jGD bdb hHB IJA IJH','heg cii abb IGf eDe hJc dii fcE'),
+ (43, 'fhf ECa FiA aDh Jbf CiB Jhe ajD','GFE bIF aeD gDE BIE Jea DfC BEc'),
+ (44, 'GjE dBj DbJ ICF aDh EEH Ejb jFb','dJj aEc IBg bEG Faf fjA hjf FAF'),
+ (45, 'BfA efd IIJ AHG dDF eGg dIJ Gcb','Bfj jeb Ahc dAE ACH Dfb ieb dhC'),
+ (46, 'Ibj ege geC dJh CIi hbD EAG fGA','DEb BFe Bjg FId Fhg HeF JAc BbE'),
+ (47, 'dhB afC hgG bEJ aIe Cbe iEE JCD','bdg Ajc FGA jbh Jge iAj fIA jbE'),
+ (48, 'egH iDi bfH iiI hGC jFF Hfd AHB','bjE Beb iCc haB gIH Dea bga dfd'),
+ (49, 'jgf chc jGc Baj HBb jdE hgh heI','FFB aBd iEB EIG HGf Bbj EIi JbI'),
+ (50, 'jhe EGi ajA fbH geh EHe FdC bij','jDE bBC gbH HeE dcH iBH IFE AHi'),
+ (51, 'aCb JiD cgJ Bjj iAI Hbe IAF FhH','ijf bhE Jdf FED dCH bbG HcJ ebH');
+ "
+}
+
+foreach_detail_mode $testprefix {
+foreach external {0 1 2} {
+ reset_db
+
+ proc tokens {cmd} {
+ set ret [list]
+ for {set iTok 0} {$iTok < [$cmd xInstCount]} {incr iTok} {
+ set txt [$cmd xInstToken $iTok 0]
+ set txt [string map [list "\0" "."] $txt]
+ lappend ret $txt
+ }
+ set ret
+ }
+ sqlite3_fts5_create_function db tokens tokens
+ sqlite3_fts5_register_origintext db
+
+ set E(0) internal
+ set E(1) external
+ set E(2) contentless
+ set e $E($external)
+
+ db eval { CREATE TABLE ex(x, y) }
+ switch -- $external {
+ 0 {
+ do_execsql_test 1.$e.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%
+ );
+ }
+ }
+
+ 1 {
+ do_execsql_test 1.$e.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
+ content=ex
+ );
+ }
+ }
+
+ 2 {
+ do_execsql_test 1.$e.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ x, y, tokenize="origintext unicode61", tokendata=1, detail=%DETAIL%,
+ content=
+ );
+ }
+ }
+ }
+ insert_data ex
+ insert_data ft
+
+ proc prefixquery {prefix bInst bYOnly} {
+ set ret [list]
+ db eval { SELECT rowid, x, y FROM ex ORDER BY rowid } {
+ set row [list]
+ set bSeen 0
+
+ set T [concat $x $y]
+ if {$bYOnly} { set T $y }
+
+ foreach w $T {
+ if {[string match -nocase $prefix $w]} {
+ set bSeen 1
+ if {$bInst} {
+ set v [string tolower $w]
+ if {$w != $v} { append v ".$w" }
+ lappend row $v
+ }
+ }
+ }
+
+ if {$bSeen} {
+ lappend ret $rowid
+ lappend ret $row
+ }
+ }
+
+ set ret
+ }
+
+ proc do_prefixquery_test {tn prefix} {
+ set bInst [expr {$::e!="contentless" || "%DETAIL%"=="full"}]
+ set expect [prefixquery $prefix $bInst 0]
+ set expect2 [prefixquery $prefix $bInst 1]
+
+ uplevel [list do_execsql_test $tn.1 "
+ SELECT rowid, tokens(ft) FROM ft('$prefix')
+ " $expect]
+ uplevel [list do_execsql_test $tn.2 "
+ SELECT rowid, tokens(ft) FROM ft(fts5_insttoken('$prefix'))
+ " $expect]
+ db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 1) }
+ uplevel [list do_execsql_test $tn.3 "
+ SELECT rowid, tokens(ft) FROM ft('$prefix')
+ " $expect]
+ db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 0) }
+
+ if {"%DETAIL%"!="none"} {
+ uplevel [list do_execsql_test $tn.4 "
+ SELECT rowid, tokens(ft) FROM ft('y: $prefix')
+ " $expect2]
+ uplevel [list do_execsql_test $tn.5 "
+ SELECT rowid, tokens(ft) FROM ft(fts5_insttoken('y: $prefix'))
+ " $expect2]
+ db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 1) }
+ uplevel [list do_execsql_test $tn.6 "
+ SELECT rowid, tokens(ft) FROM ft('y: $prefix')
+ " $expect2]
+ db eval { INSERT INTO ft(ft, rank) VALUES('insttoken', 0) }
+ }
+ }
+
+ do_prefixquery_test 1.$e.1 a*
+ do_prefixquery_test 1.$e.2 b*
+ do_prefixquery_test 1.$e.3 c*
+ do_prefixquery_test 1.$e.4 d*
+ do_prefixquery_test 1.$e.5 e*
+ do_prefixquery_test 1.$e.6 f*
+ do_prefixquery_test 1.$e.7 g*
+ do_prefixquery_test 1.$e.8 h*
+ do_prefixquery_test 1.$e.9 i*
+ do_prefixquery_test 1.$e.10 j*
+}}
+
+
+
+finish_test
+
diff --git a/ext/fts5/test/fts5phrase.test b/ext/fts5/test/fts5phrase.test
index 10598ccf43..708cdfd83e 100644
--- a/ext/fts5/test/fts5phrase.test
+++ b/ext/fts5/test/fts5phrase.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5phrase
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -93,15 +93,21 @@ foreach {tn cols tokens} {
10 {b} "i e"
11 {a} "i e"
} {
- set fts "{$cols}:[join $tokens +]"
set where [list]
foreach c $cols { lappend where "pmatch($c, '$tokens')" }
set where [join $where " OR "]
- set res [db eval "SELECT rowid FROM t3 WHERE $where"]
- do_execsql_test "1.$tn.$fts->([llength $res] rows)" {
- SELECT rowid FROM t3($fts)
- } $res
+ foreach fts [list \
+ "{$cols}:[join $tokens +]" \
+ "{$cols}:NEAR([join $tokens +])" \
+ "{$cols}:NEAR([join $tokens +],1)" \
+ "{$cols}:NEAR([join $tokens +],111)" \
+ ] {
+ set res [db eval "SELECT rowid FROM t3 WHERE $where"]
+ do_execsql_test "1.$tn.$fts->([llength $res] rows)" {
+ SELECT rowid FROM t3($fts)
+ } $res
+ }
}
do_execsql_test 2.0 {
diff --git a/ext/fts5/test/fts5plan.test b/ext/fts5/test/fts5plan.test
index 6862acf179..57d5254a35 100644
--- a/ext/fts5/test/fts5plan.test
+++ b/ext/fts5/test/fts5plan.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5plan
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5porter.test b/ext/fts5/test/fts5porter.test
index c7b1ce6f3f..de1c3e15a3 100644
--- a/ext/fts5/test/fts5porter.test
+++ b/ext/fts5/test/fts5porter.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5porter
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5porter2.test b/ext/fts5/test/fts5porter2.test
index 6e81b2d310..556060baa3 100644
--- a/ext/fts5/test/fts5porter2.test
+++ b/ext/fts5/test/fts5porter2.test
@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5porter2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5prefix.test b/ext/fts5/test/fts5prefix.test
index 279f312f22..7a29628ea1 100644
--- a/ext/fts5/test/fts5prefix.test
+++ b/ext/fts5/test/fts5prefix.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5prefix
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5prefix2.test b/ext/fts5/test/fts5prefix2.test
index 29744c86bf..0860b3cddd 100644
--- a/ext/fts5/test/fts5prefix2.test
+++ b/ext/fts5/test/fts5prefix2.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5prefix2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5query.test b/ext/fts5/test/fts5query.test
index 5237e8e250..4e8bab8cf7 100644
--- a/ext/fts5/test/fts5query.test
+++ b/ext/fts5/test/fts5query.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5query
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5rank.test b/ext/fts5/test/fts5rank.test
index 8cf223f44b..7a700cb97f 100644
--- a/ext/fts5/test/fts5rank.test
+++ b/ext/fts5/test/fts5rank.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rank
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5rebuild.test b/ext/fts5/test/fts5rebuild.test
index ae881c02f0..d74b148fb1 100644
--- a/ext/fts5/test/fts5rebuild.test
+++ b/ext/fts5/test/fts5rebuild.test
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rebuild
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5restart.test b/ext/fts5/test/fts5restart.test
index db2c62b675..da58fe3aed 100644
--- a/ext/fts5/test/fts5restart.test
+++ b/ext/fts5/test/fts5restart.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5restart
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -29,6 +29,7 @@ do_execsql_test 1.0 {
# Run the 'optimize' command. Check that it does not disturb ongoing
# full-text queries.
#
+unset -nocomplain lRowid
do_test 1.1 {
for {set i 1} {$i < 1000} {incr i} {
execsql { INSERT INTO f1 VALUES('a b c d e') }
diff --git a/ext/fts5/test/fts5rowid.test b/ext/fts5/test/fts5rowid.test
index 8935ecfea7..e4e4f6b844 100644
--- a/ext/fts5/test/fts5rowid.test
+++ b/ext/fts5/test/fts5rowid.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rowid
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5savepoint.test b/ext/fts5/test/fts5savepoint.test
index 1126222750..bf66052282 100644
--- a/ext/fts5/test/fts5savepoint.test
+++ b/ext/fts5/test/fts5savepoint.test
@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5savepoint
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -48,7 +48,7 @@ do_catchsql_test 2.0 {
SAVEPOINT two;
INSERT INTO ft1 VALUES('b');
COMMIT;
-} {1 {SQL logic error}}
+} {1 {database disk image is malformed}}
reset_db
ifcapable fts3 {
diff --git a/ext/fts5/test/fts5secure3.test b/ext/fts5/test/fts5secure3.test
index bc56e08200..49347144f3 100644
--- a/ext/fts5/test/fts5secure3.test
+++ b/ext/fts5/test/fts5secure3.test
@@ -86,71 +86,76 @@ do_execsql_test 2.8 {
# Tests with large/small rowid values.
#
-reset_db
-
-expr srand(0)
-
-set vocab {
- Popper Poppins Popsicle Porfirio Porrima Porsche
- Porter Portia Portland Portsmouth Portugal Portuguese
- Poseidon Post PostgreSQL Potemkin Potomac Potsdam
- Pottawatomie Potter Potts Pound Poussin Powell
- PowerPC PowerPoint Powers Powhatan Poznan Prada
- Prado Praetorian Prague Praia Prakrit Pratchett
- Pratt Pravda Praxiteles Preakness Precambrian Preminger
- Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
-}
-proc newdoc {} {
- for {set i 0} {$i<8} {incr i} {
- lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
+foreach {tn cfg} {
+ 1 ""
+ 2 "INSERT INTO fff(fff, rank) VALUES('secure-delete', 1)"
+} {
+ reset_db
+
+ expr srand(0)
+
+ set vocab {
+ Popper Poppins Popsicle Porfirio Porrima Porsche
+ Porter Portia Portland Portsmouth Portugal Portuguese
+ Poseidon Post PostgreSQL Potemkin Potomac Potsdam
+ Pottawatomie Potter Potts Pound Poussin Powell
+ PowerPC PowerPoint Powers Powhatan Poznan Prada
+ Prado Praetorian Prague Praia Prakrit Pratchett
+ Pratt Pravda Praxiteles Preakness Precambrian Preminger
+ Premyslid Prensa Prentice Pres Presbyterian Presbyterianism
}
- set ret
-}
-db func newdoc newdoc
-
-do_execsql_test 3.0 {
- CREATE VIRTUAL TABLE fff USING fts5(y);
- INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
-
- WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
- INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
-
- WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
- INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
-
- WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
- INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
-
- INSERT INTO fff(fff, rank) VALUES('secure-delete', 1);
-}
-
-proc lshuffle {in} {
- set out [list]
- while {[llength $in]>0} {
- set idx [expr int(abs(rand()) * [llength $in])]
- lappend out [lindex $in $idx]
- set in [lreplace $in $idx $idx]
+ proc newdoc {} {
+ for {set i 0} {$i<8} {incr i} {
+ lappend ret [lindex $::vocab [expr int(abs(rand()) * [llength $::vocab])]]
+ }
+ set ret
+ }
+ db func newdoc newdoc
+
+ do_execsql_test 3.$tn.0 {
+ CREATE VIRTUAL TABLE fff USING fts5(y);
+ INSERT INTO fff(fff, rank) VALUES('pgsz', 64);
+
+ WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
+ INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
+
+ WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
+ INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
+
+ WITH s(x) AS ( VALUES(1) UNION ALL SELECT x+1 FROM s WHERE x<1000 )
+ INSERT INTO fff(rowid, y) SELECT random() , newdoc() FROM s;
}
- set out
-}
-
-#dump fff
-set iTest 1
-foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
- #if {$iTest==1} { dump fff }
- #if {$iTest==1} { breakpoint }
- do_execsql_test 3.1.$iTest.$ii {
- DELETE FROM fff WHERE rowid=$ii;
+ execsql $cfg
+
+ proc lshuffle {in} {
+ set out [list]
+ while {[llength $in]>0} {
+ set idx [expr int(abs(rand()) * [llength $in])]
+ lappend out [lindex $in $idx]
+ set in [lreplace $in $idx $idx]
+ }
+ set out
}
- #if {$iTest==1} { dump fff }
- if {($iTest % 20)==0} {
- do_execsql_test 3.1.$iTest.$ii.ic {
- INSERT INTO fff(fff) VALUES('integrity-check');
+
+ #dump fff
+
+ set iTest 1
+ foreach ii [lshuffle [db eval {SELECT rowid FROM fff}]] {
+ #if {$iTest==1} { dump fff }
+ #if {$iTest==1} { breakpoint }
+ do_execsql_test 3.$tn.1.$iTest.$ii {
+ DELETE FROM fff WHERE rowid=$ii;
+ }
+ #if {$iTest==1} { dump fff }
+ if {($iTest % 20)==0} {
+ do_execsql_test 3.$tn.1.$iTest.$ii.ic {
+ INSERT INTO fff(fff) VALUES('integrity-check');
+ }
}
+ #if {$iTest==1} { break }
+ incr iTest
}
- #if {$iTest==1} { break }
- incr iTest
}
#execsql_pp { SELECT rowid FROM fff('post') ORDER BY rowid ASC }
diff --git a/ext/fts5/test/fts5secure8.test b/ext/fts5/test/fts5secure8.test
index 8ceb9630aa..8b65b7c59f 100644
--- a/ext/fts5/test/fts5secure8.test
+++ b/ext/fts5/test/fts5secure8.test
@@ -42,6 +42,26 @@ do_execsql_test 1.2 {
PRAGMA integrity_check;
} {ok}
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE xyz USING fts5 (
+ name,
+ content=''
+ );
+
+ INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 1);
+ INSERT INTO xyz (rowid, name) VALUES(1, 'A');
+ INSERT INTO xyz (rowid, name) VALUES(2, 'A');
+ INSERT INTO xyz(xyz, rowid, name) VALUES('delete', 2, 'A');
+}
+
+do_execsql_test 2.1 {
+ pragma quick_check;
+} {ok}
+
+do_catchsql_test 2.2 {
+ INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 'hello world');
+} {1 {SQL logic error}}
+
diff --git a/ext/fts5/test/fts5securefault.test b/ext/fts5/test/fts5securefault.test
index 63874ece5d..2959ab65ce 100644
--- a/ext/fts5/test/fts5securefault.test
+++ b/ext/fts5/test/fts5securefault.test
@@ -16,7 +16,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5securefault
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
return_if_no_fts5
do_execsql_test 1.0 {
diff --git a/ext/fts5/test/fts5simple.test b/ext/fts5/test/fts5simple.test
index 936bbb2549..ad59bf0d9e 100644
--- a/ext/fts5/test/fts5simple.test
+++ b/ext/fts5/test/fts5simple.test
@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -350,7 +350,7 @@ do_execsql_test 14.3 {
do_execsql_test 14.4 {
SELECT rowid, x, x1 FROM x1 WHERE x1 MATCH '*reads'
-} {0 {} 3}
+} {0 {} 2}
#-------------------------------------------------------------------------
reset_db
@@ -480,4 +480,33 @@ do_execsql_test 22.0 {
do_catchsql_test 22.1 {SELECT * FROM x1('')} {1 {fts5: syntax error near ""}}
do_catchsql_test 22.2 {SELECT * FROM x1(NULL)} {1 {fts5: syntax error near ""}}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 23.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(x);
+ SELECT count(*) FROM x1_data;
+} {2}
+
+do_execsql_test 23.1 {
+ BEGIN;
+ INSERT INTO x1 VALUES('a b c d');
+ INSERT INTO x1 VALUES('a b c d');
+ INSERT INTO x1 VALUES('a b c d');
+}
+
+do_execsql_test 23.2 {
+ SELECT count(*) FROM x1_data;
+} {2}
+
+do_execsql_test 23.3 {
+ INSERT INTO x1(x1) VALUES('flush');
+ SELECT count(*) FROM x1_data;
+} {3}
+
+do_execsql_test 23.4 {
+ ROLLBACK;
+ SELECT count(*) FROM x1_data;
+} {2}
+
+
finish_test
diff --git a/ext/fts5/test/fts5simple2.test b/ext/fts5/test/fts5simple2.test
index e57cea70fa..01c590c9f7 100644
--- a/ext/fts5/test/fts5simple2.test
+++ b/ext/fts5/test/fts5simple2.test
@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -343,7 +343,9 @@ do_execsql_test 17.0 {
INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
COMMIT;
}
-do_execsql_test 17.1 { SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20 }
+do_execsql_test 17.1 {
+ SELECT * FROM t2('y:a*') WHERE rowid BETWEEN 10 AND 20
+}
do_execsql_test 17.2 {
BEGIN;
INSERT INTO t2 VALUES('a aa aaa', 'b bb bbb');
diff --git a/ext/fts5/test/fts5simple3.test b/ext/fts5/test/fts5simple3.test
index 0d4972b372..680448081d 100644
--- a/ext/fts5/test/fts5simple3.test
+++ b/ext/fts5/test/fts5simple3.test
@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple3
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5synonym.test b/ext/fts5/test/fts5synonym.test
index 86610ee9eb..55e2f186a9 100644
--- a/ext/fts5/test/fts5synonym.test
+++ b/ext/fts5/test/fts5synonym.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5synonym
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5synonym2.test b/ext/fts5/test/fts5synonym2.test
index 2c2705e34f..ec8b750c57 100644
--- a/ext/fts5/test/fts5synonym2.test
+++ b/ext/fts5/test/fts5synonym2.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5synonym2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -42,7 +42,7 @@ proc fts5_test_bothlist {cmd} {
}
sqlite3_fts5_create_function db fts5_test_bothlist fts5_test_bothlist
-proc fts5_rowid {cmd} { expr [$cmd xColumnText -1] }
+proc fts5_rowid {cmd} { expr [$cmd xRowid] }
sqlite3_fts5_create_function db fts5_rowid fts5_rowid
do_execsql_test 1.$tok.0.1 "
diff --git a/ext/fts5/test/fts5tokendata.test b/ext/fts5/test/fts5tokendata.test
new file mode 100644
index 0000000000..7f75f4fa8e
--- /dev/null
+++ b/ext/fts5/test/fts5tokendata.test
@@ -0,0 +1,105 @@
+# 2014 Jan 08
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focused on phrase queries.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5tokendata
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+foreach_detail_mode $testprefix {
+
+ sqlite3_fts5_register_origintext db
+ fts5_aux_test_functions db
+ proc b {x} { string map [list "\0" "."] $x }
+ db func b b
+
+ do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a, b, tokendata=1,
+ tokenize="origintext unicode61", detail=%DETAIL%
+ );
+ CREATE VIRTUAL TABLE vocab USING fts5vocab(ft, instance);
+ }
+
+ do_execsql_test 1.1 {
+ INSERT INTO ft(rowid, a, b) VALUES
+ (1, 'Pedagog Pedal Pedant', 'Peculier Day Today'),
+ (2, 'Pedant pedantic pecked', 'Peck Penalize Pen');
+
+ INSERT INTO ft(rowid, a, b) VALUES
+ (3, 'Penalty Pence Penciled', 'One Two Three'),
+ (4, 'Pedant Pedal Pedant', 'Peculier Day Today');
+ }
+
+ do_execsql_test 1.2 {
+ SELECT DISTINCT b(term) FROM vocab
+ } {
+ day.Day one.One peck.Peck pecked peculier.Peculier pedagog.Pedagog
+ pedal.Pedal pedant.Pedant pedantic pen.Pen penalize.Penalize
+ penalty.Penalty pence.Pence penciled.Penciled three.Three
+ today.Today two.Two
+ }
+
+ do_execsql_test 1.3.1 {
+ SELECT rowid FROM ft('pe*')
+ } {
+ 1 2 3 4
+ }
+
+ do_execsql_test 1.3.2 {
+ SELECT rowid FROM ft('pe*') ORDER BY rowid DESC
+ } {
+ 4 3 2 1
+ }
+
+ if {"%DETAIL%"!="none"} {
+ do_execsql_test 1.3.3 {
+ SELECT rowid FROM ft WHERE a MATCH 'pe*' ORDER BY rowid DESC
+ } {
+ 4 3 2 1
+ }
+ }
+
+ do_execsql_test 1.4 {
+ SELECT rowid, b( fts5_test_insttoken(ft, 0, 0) ) FROM ft('pedant')
+ } {
+ 1 pedant.Pedant
+ 2 pedant.Pedant
+ 4 pedant.Pedant
+ }
+
+ do_execsql_test 1.5 {
+ SELECT rowid, b( fts5_test_insttoken(ft, 0, 0) ) FROM ft('pe*')
+ } {
+ 1 pedagog.Pedagog
+ 2 pedant.Pedant
+ 3 penalty.Penalty
+ 4 pedant.Pedant
+ }
+
+ do_execsql_test 1.6 {
+ SELECT rowid, fts5_test_poslist(ft) FROM ft('pe*')
+ } {
+ 1 {0.0.0 0.0.1 0.0.2 0.1.0}
+ 2 {0.0.0 0.0.1 0.0.2 0.1.0 0.1.1 0.1.2}
+ 3 {0.0.0 0.0.1 0.0.2}
+ 4 {0.0.0 0.0.1 0.0.2 0.1.0}
+ }
+}
+
+finish_test
+
diff --git a/ext/fts5/test/fts5tokenizer.test b/ext/fts5/test/fts5tokenizer.test
index 27370657ed..a828e3a22b 100644
--- a/ext/fts5/test/fts5tokenizer.test
+++ b/ext/fts5/test/fts5tokenizer.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5tokenizer
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -300,5 +300,75 @@ set ::flags [list]
do_execsql_test 9.5.1 { SELECT * FROM t1('"abc xyz*"'); } {}
do_test 9.5.2 { set ::flags } {query}
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 10.1 {
+ CREATE VIRTUAL TABLE x1 USING fts5(x, tokenize=unicode61);
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_schema
+ SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(x, tokenize="unicode61 error");'
+ WHERE name = 'x1';
+}
+
+db close
+sqlite3 db test.db
+
+do_catchsql_test 10.2 {
+ SELECT * FROM x1('abc');
+} {1 {error in tokenizer constructor}}
+
+do_catchsql_test 10.3 {
+ INSERT INTO x1 VALUES('abc');
+} {1 {error in tokenizer constructor}}
+
+do_execsql_test 10.4 {
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_schema
+ SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(x, tokenize="nosuch error");'
+ WHERE name = 'x1';
+}
+
+db close
+sqlite3 db test.db
+
+do_catchsql_test 10.5 {
+ SELECT * FROM x1('abc');
+} {1 {no such tokenizer: nosuch}}
+do_catchsql_test 10.6 {
+ INSERT INTO x1 VALUES('abc');
+} {1 {no such tokenizer: nosuch}}
+
+do_execsql_test 10.7 {
+ DROP TABLE x1;
+ SELECT * FROM sqlite_schema;
+}
+
+reset_db
+do_execsql_test 10.8 {
+ CREATE VIRTUAL TABLE x1 USING fts5(x, tokenize=unicode61);
+ INSERT INTO x1 VALUES('a b c'), ('d e f'), ('a b c');
+ CREATE VIRTUAL TABLE x1v USING fts5vocab(x1, row);
+
+ PRAGMA writable_schema = 1;
+ UPDATE sqlite_schema
+ SET sql = 'CREATE VIRTUAL TABLE x1 USING fts5(x, tokenize=simplify);'
+ WHERE name = 'x1';
+}
+
+do_execsql_test 10.9 {
+ SELECT * FROM x1v
+} {
+ a 2 2 b 2 2 c 2 2 d 1 1 e 1 1 f 1 1
+}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 10.10 {
+ SELECT * FROM x1v
+} {
+ a 2 2 b 2 2 c 2 2 d 1 1 e 1 1 f 1 1
+}
finish_test
diff --git a/ext/fts5/test/fts5tokenizer2.test b/ext/fts5/test/fts5tokenizer2.test
new file mode 100644
index 0000000000..4fe31d22c4
--- /dev/null
+++ b/ext/fts5/test/fts5tokenizer2.test
@@ -0,0 +1,109 @@
+# 2023 Nov 03
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focusing on the built-in fts5 tokenizers.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5tokenizer2
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+sqlite3_fts5_create_tokenizer db tst get_tst_tokenizer
+proc get_tst_tokenizer {args} {
+ return "tst_tokenizer"
+}
+proc tst_tokenizer {flags txt} {
+ set token ""
+ set lTok [list]
+
+ foreach c [split $txt {}] {
+ if {$token==""} {
+ append token $c
+ } else {
+ set t1 [string is upper $token]
+ set t2 [string is upper $c]
+
+ if {$t1!=$t2} {
+ lappend lTok $token
+ set token ""
+ }
+ append token $c
+ }
+ }
+ if {$token!=""} { lappend lTok $token }
+
+ set iOff 0
+ foreach t $lTok {
+ set n [string length $t]
+ sqlite3_fts5_token $t $iOff [expr $iOff+$n]
+ incr iOff $n
+ }
+}
+
+do_execsql_test 1.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(t, tokenize=tst);
+}
+
+do_execsql_test 1.1 {
+ INSERT INTO t1 VALUES('AAdontBBmess');
+}
+
+do_execsql_test 1.2 {
+ SELECT snippet(t1, 0, '>', '<', '...', 4) FROM t1('BB');
+} {AAdont>BB', '<') FROM t1('BB');
+} {AAdont>BB', '<') FROM t1('AA');
+} {>AA', '<') FROM t1('dont');
+} {AA>dont', '<') FROM t1('mess');
+} {AAdontBB>mess<}
+
+do_execsql_test 1.7 {
+ SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
+} {AAdont>BBmess<}
+
+# 2024-08-06 https://sqlite.org/forum/forumpost/171bcc2bcd
+# Error handling of tokenize= arguments.
+#
+foreach {n tkz} {
+ 1 {ascii none}
+ 2 {unicode61 none}
+ 3 {porter none}
+ 4 {trigram none}
+ 5 {ascii none 0}
+ 6 {unicode61 none 0}
+ 7 {porter none 0}
+ 8 {trigram none 0}
+} {
+ db eval {DROP TABLE IF EXISTS t2;}
+ do_catchsql_test 2.$n "
+ DROP TABLE IF EXISTS t2;
+ CREATE VIRTUAL TABLE t2 USING fts5(a,b,c,tokenize='$tkz');
+ " {1 {error in tokenizer constructor}}
+}
+
+
+finish_test
diff --git a/ext/fts5/test/fts5tokenizer3.test b/ext/fts5/test/fts5tokenizer3.test
new file mode 100644
index 0000000000..5cdab743c2
--- /dev/null
+++ b/ext/fts5/test/fts5tokenizer3.test
@@ -0,0 +1,77 @@
+# 2024 Aug 10
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Tests focusing on the built-in fts5 tokenizers.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5tokenizer3
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+
+proc get_sod {args} { return "split_on_dot" }
+proc get_lowercase {args} { return "lowercase" }
+
+proc lowercase {flags txt} {
+ set n [string length $txt]
+ sqlite3_fts5_token [string tolower $txt] 0 $n
+ return 0
+}
+
+proc split_on_dot {flags txt} {
+ set iOff 0
+ foreach t [split $txt "."] {
+ set n [string length $txt]
+ sqlite3_fts5_token $t $iOff [expr $iOff+$n]
+ incr iOff [expr {$n+1}]
+ }
+ return ""
+}
+
+foreach {tn script} {
+ 1 {
+ sqlite3_fts5_create_tokenizer db lowercase get_lowercase
+ sqlite3_fts5_create_tokenizer -parent lowercase db split_on_dot get_sod
+ }
+ 2 {
+ sqlite3_fts5_create_tokenizer -v2 db lowercase get_lowercase
+ sqlite3_fts5_create_tokenizer -parent lowercase db split_on_dot get_sod
+ }
+ 3 {
+ sqlite3_fts5_create_tokenizer db lowercase get_lowercase
+ sqlite3_fts5_create_tokenizer -v2 -parent lowercase db split_on_dot get_sod
+ }
+ 4 {
+ sqlite3_fts5_create_tokenizer -v2 db lowercase get_lowercase
+ sqlite3_fts5_create_tokenizer -v2 -parent lowercase db split_on_dot get_sod
+ }
+} {
+ reset_db
+ eval $script
+
+ do_execsql_test 1.$tn.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize=split_on_dot);
+ CREATE VIRTUAL TABLE t1vocab USING fts5vocab(t1, instance);
+ INSERT INTO t1 VALUES('ABC.Def.ghi');
+ }
+
+ do_execsql_test 1.$tn.1 {
+ SELECT term FROM t1vocab ORDER BY 1
+ } {abc def ghi}
+}
+
+
+finish_test
diff --git a/ext/fts5/test/fts5trigram.test b/ext/fts5/test/fts5trigram.test
index 351c059bf5..377e3f7813 100644
--- a/ext/fts5/test/fts5trigram.test
+++ b/ext/fts5/test/fts5trigram.test
@@ -56,6 +56,7 @@ foreach {tn like res} {
7 {ABCDEFG%} 1
8 {%รุงเ%} 2
9 {%งเ%} 2
+ 10 {%"งเ"%} {}
} {
do_execsql_test 1.3.$tn {
SELECT rowid FROM t1 WHERE y LIKE $like
@@ -69,6 +70,9 @@ do_execsql_test 2.0 {
INSERT INTO t1 VALUES('abcdefghijklm');
INSERT INTO t1 VALUES('กรุงเทพมหานคร');
}
+do_catchsql_test 2.0.1 {
+ CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram case_sensitive');
+} {1 {error in tokenizer constructor}}
foreach {tn s res} {
1 abc "(abc)defghijklm"
@@ -197,6 +201,12 @@ do_eqp_test 6.3 {
do_eqp_test 6.4 {
SELECT * FROM ci1 WHERE x GLOB ?
} {VIRTUAL TABLE INDEX 0:G0}
+do_eqp_test 6.5 {
+ SELECT * FROM ci1 WHERE x < ?
+} {{SCAN ci1 VIRTUAL TABLE INDEX 0:}}
+do_eqp_test 6.6 {
+ SELECT * FROM ci0 WHERE x < ?
+} {{SCAN ci0 VIRTUAL TABLE INDEX 0:}}
reset_db
do_execsql_test 7.0 {
@@ -206,7 +216,7 @@ do_execsql_test 7.0 {
(20, "жираф.png"),
(30, "cat.png"),
(40, "кот.png"),
- (50, "misic-🎵-.mp3");
+ (50, "misic-ðµ-.mp3");
}
do_execsql_test 7.1 {
SELECT rowid FROM f WHERE +filename GLOB '*ир*';
@@ -253,4 +263,104 @@ do_execsql_test 8.3 {
{[abcde]}
}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 9.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(
+ a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
+ tokenize=trigram
+ );
+
+ INSERT INTO t1(rowid, a12) VALUES(111, 'thats a tricky case though');
+ INSERT INTO t1(rowid, a12) VALUES(222, 'the query planner cannot do');
+}
+
+do_execsql_test 9.1 {
+ SELECT rowid FROM t1 WHERE a12 LIKE '%tricky%'
+} {111}
+
+do_execsql_test 9.2 {
+ SELECT rowid FROM t1 WHERE a12 LIKE '%tricky%' AND a12 LIKE '%case%'
+} {111}
+
+do_execsql_test 9.3 {
+ SELECT rowid FROM t1 WHERE a12 LIKE NULL
+} {}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 10.0 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=trigram);
+}
+
+do_test 10.1 {
+ foreach {val} {
+ "abc \UFFjkl\UFF"
+ "abc \UFFFjkl\UFFF"
+ "abc \UFFFFjkl\UFFFF"
+ "abc \UFFFFFjkl\UFFFFF"
+ "\UFFjkl\UFF abc"
+ "\UFFFjkl\UFFF abc"
+ "\UFFFFjkl\UFFFF abc"
+ "\UFFFFFjkl\UFFFFF abc"
+ "\U10001jkl\U10001 abc"
+ } {
+ execsql { INSERT INTO t1 VALUES( $val ) }
+ }
+} {}
+
+do_test 10.2 {
+ foreach {val} {
+ X'E18000626320646566'
+ X'61EDA0806320646566'
+ X'61EDA0806320646566'
+ X'61EFBFBE6320646566'
+ X'76686920E18000626320646566'
+ X'7668692061EDA0806320646566'
+ X'7668692061EDA0806320646566'
+ X'7668692061EFBFBE6320646566'
+ } {
+ execsql " INSERT INTO t1 VALUES( $val ) "
+ }
+} {}
+
+do_test 10.3 {
+ set a [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0x62}]
+ set b [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0x62}]
+ set c [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}]
+ set d [binary format c* {0x61 0xF7 0xBF 0xBF 0xBF 0xBF 0xBF 0xBF 0x62}]
+ execsql {
+ INSERT INTO t1 VALUES($a);
+ INSERT INTO t1 VALUES($b);
+ INSERT INTO t1 VALUES($c);
+ INSERT INTO t1 VALUES($d);
+
+ INSERT INTO t1 VALUES('abcd' || $a);
+ INSERT INTO t1 VALUES('abcd' || $b);
+ INSERT INTO t1 VALUES('abcd' || $c);
+ INSERT INTO t1 VALUES('abcd' || $d);
+ }
+} {}
+
+do_execsql_test 11.0 {
+ CREATE VIRTUAL TABLE t4 USING fts5(y, tokenize=trigram);
+}
+sqlite3_fts5_register_str db
+do_execsql_test 11.1 {
+ INSERT INTO t4 VALUES( str('') );
+}
+
+do_test 12.0 {
+ sqlite3_fts5_tokenize db trigram "abcd"
+} {abc 0 3 bcd 1 4}
+
+do_test 12.1 {
+ sqlite3_fts5_tokenize db trigram "a"
+} {}
+
+do_test 12.2 {
+ sqlite3_fts5_tokenize db trigram ""
+} {}
+
finish_test
+
diff --git a/ext/fts5/test/fts5trigram2.test b/ext/fts5/test/fts5trigram2.test
new file mode 100644
index 0000000000..c81684a22b
--- /dev/null
+++ b/ext/fts5/test/fts5trigram2.test
@@ -0,0 +1,137 @@
+# 2023 October 24
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+#
+# Tests for the fts5 "trigram" tokenizer.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+ifcapable !fts5 { finish_test ; return }
+set ::testprefix fts5trigram2
+
+do_execsql_test 1.0 "
+ CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
+ INSERT INTO t1 VALUES('abc\u0303defghijklm');
+ INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
+"
+do_catchsql_test 1.0.1 {
+ CREATE VIRTUAL TABLE t2 USING fts5(z, tokenize='trigram remove_diacritics');
+} {1 {error in tokenizer constructor}}
+
+do_execsql_test 1.1 {
+ SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
+} [list \
+ "(abc\u0303)defghijklm" \
+ "(a\u0303b\u0303c\u0303)defghijklm" \
+]
+
+do_execsql_test 1.2 {
+ SELECT highlight(t1, 0, '(', ')') FROM t1('bcde');
+} [list \
+ "a(bc\u0303de)fghijklm" \
+ "a\u0303(b\u0303c\u0303de)fghijklm" \
+]
+
+do_execsql_test 1.3 {
+ SELECT highlight(t1, 0, '(', ')') FROM t1('cdef');
+} [list \
+ "ab(c\u0303def)ghijklm" \
+ "a\u0303b\u0303(c\u0303def)ghijklm" \
+]
+
+do_execsql_test 1.4 {
+ SELECT highlight(t1, 0, '(', ')') FROM t1('def');
+} [list \
+ "abc\u0303(def)ghijklm" \
+ "a\u0303b\u0303c\u0303(def)ghijklm" \
+]
+
+
+#-------------------------------------------------------------------------
+do_catchsql_test 2.0 {
+ CREATE VIRTUAL TABLE t2 USING fts5(
+ z, tokenize='trigram case_sensitive 1 remove_diacritics 1'
+ );
+} {1 {error in tokenizer constructor}}
+
+do_execsql_test 2.1 {
+ CREATE VIRTUAL TABLE t2 USING fts5(
+ z, tokenize='trigram case_sensitive 0 remove_diacritics 1'
+ );
+}
+do_execsql_test 2.2 "
+ INSERT INTO t2 VALUES('\u00E3bcdef');
+ INSERT INTO t2 VALUES('b\u00E3cdef');
+ INSERT INTO t2 VALUES('bc\u00E3def');
+ INSERT INTO t2 VALUES('bcd\u00E3ef');
+"
+
+do_execsql_test 2.3 {
+ SELECT highlight(t2, 0, '(', ')') FROM t2('abc');
+} "(\u00E3bc)def"
+do_execsql_test 2.4 {
+ SELECT highlight(t2, 0, '(', ')') FROM t2('bac');
+} "(b\u00E3c)def"
+do_execsql_test 2.5 {
+ SELECT highlight(t2, 0, '(', ')') FROM t2('bca');
+} "(bc\u00E3)def"
+do_execsql_test 2.6 "
+ SELECT highlight(t2, 0, '(', ')') FROM t2('\u00E3bc');
+" "(\u00E3bc)def"
+
+#-------------------------------------------------------------------------
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE t3 USING fts5(
+ z, tokenize='trigram remove_diacritics 1'
+ );
+} {}
+do_execsql_test 3.1 "
+ INSERT INTO t3 VALUES ('\u0303abc\u0303');
+"
+do_execsql_test 3.2 {
+ SELECT highlight(t3, 0, '(', ')') FROM t3('abc');
+} "\u0303(abc\u0303)"
+
+#-------------------------------------------------------------------------
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE t4 USING fts5(z, tokenize=trigram);
+} {}
+
+do_execsql_test 4.1 {
+ INSERT INTO t4 VALUES('ABCD');
+ INSERT INTO t4 VALUES('DEFG');
+} {}
+
+db close
+sqlite3 db test.db
+
+do_eqp_test 4.1 {
+ SELECT rowid FROM t4 WHERE z LIKE '%abc%'
+} {VIRTUAL TABLE INDEX 0:L0}
+
+do_execsql_test 4.2 {
+ SELECT rowid FROM t4 WHERE z LIKE '%abc%'
+} {1}
+
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 5.0 {
+ CREATE VIRTUAL TABLE t5 USING fts5(
+ c1, tokenize='trigram', detail='none'
+ );
+ INSERT INTO t5(rowid, c1) VALUES(1, 'abc_____xyx_yxz');
+ INSERT INTO t5(rowid, c1) VALUES(2, 'abc_____xyxz');
+ INSERT INTO t5(rowid, c1) VALUES(3, 'ac_____xyxz');
+} {}
+do_execsql_test 5.1 {
+ SELECT rowid FROM t5 WHERE c1 LIKE 'abc%xyxz'
+} {2}
+
+finish_test
diff --git a/ext/fts5/test/fts5ubsan.test b/ext/fts5/test/fts5ubsan.test
index 2dc0aa7bd4..76382a1e15 100644
--- a/ext/fts5/test/fts5ubsan.test
+++ b/ext/fts5/test/fts5ubsan.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ubsan
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5unicode.test b/ext/fts5/test/fts5unicode.test
index e2d0f60124..f10e0d02d8 100644
--- a/ext/fts5/test/fts5unicode.test
+++ b/ext/fts5/test/fts5unicode.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5unicode
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -60,6 +60,7 @@ do_execsql_test 2.1 "
# require 17 or more bits to store).
#
+unset -nocomplain A B C D
set A [db one {SELECT char(0x1F75E)}] ;# Type So
set B [db one {SELECT char(0x1F5FD)}] ;# Type So
set C [db one {SELECT char(0x2F802)}] ;# Type Lo
diff --git a/ext/fts5/test/fts5unicode2.test b/ext/fts5/test/fts5unicode2.test
index 662b9dd87b..7a49a1d83f 100644
--- a/ext/fts5/test/fts5unicode2.test
+++ b/ext/fts5/test/fts5unicode2.test
@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5unicode2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -116,6 +116,7 @@ set docs [list {
connected by OR.
}]
+unset -nocomplain map
set map(a) [list "\u00C4" "\u00E4"] ; # LATIN LETTER A WITH DIAERESIS
set map(e) [list "\u00CB" "\u00EB"] ; # LATIN LETTER E WITH DIAERESIS
set map(i) [list "\u00CF" "\u00EF"] ; # LATIN LETTER I WITH DIAERESIS
@@ -470,119 +471,23 @@ do_execsql_test 8.2.3 {
} {2 4}
#-------------------------------------------------------------------------
-#
-if 0 {
-foreach {tn sql} {
- 1 {
- CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 [tokenchars= .]);
- CREATE VIRTUAL TABLE t6 USING fts4(
- tokenize=unicode61 [tokenchars=="] "tokenchars=[]");
- CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 [separators=x\xC4]);
- }
- 2 {
- CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 "tokenchars= .");
- CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 "tokenchars=[=""]");
- CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 "separators=x\xC4");
- }
- 3 {
- CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 'tokenchars= .');
- CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 'tokenchars=="[]');
- CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 'separators=x\xC4');
- }
- 4 {
- CREATE VIRTUAL TABLE t5 USING fts4(tokenize=unicode61 `tokenchars= .`);
- CREATE VIRTUAL TABLE t6 USING fts4(tokenize=unicode61 `tokenchars=[="]`);
- CREATE VIRTUAL TABLE t7 USING fts4(tokenize=unicode61 `separators=x\xC4`);
- }
-} {
- do_execsql_test 9.$tn.0 {
- DROP TABLE IF EXISTS t5;
- DROP TABLE IF EXISTS t5aux;
- DROP TABLE IF EXISTS t6;
- DROP TABLE IF EXISTS t6aux;
- DROP TABLE IF EXISTS t7;
- DROP TABLE IF EXISTS t7aux;
- }
- do_execsql_test 9.$tn.1 $sql
-
- do_execsql_test 9.$tn.2 {
- CREATE VIRTUAL TABLE t5aux USING fts4aux(t5);
- INSERT INTO t5 VALUES('one two three/four.five.six');
- SELECT * FROM t5aux;
- } {
- four.five.six * 1 1 four.five.six 0 1 1
- {one two three} * 1 1 {one two three} 0 1 1
- }
-
- do_execsql_test 9.$tn.3 {
- CREATE VIRTUAL TABLE t6aux USING fts4aux(t6);
- INSERT INTO t6 VALUES('alpha=beta"gamma/delta[epsilon]zeta');
- SELECT * FROM t6aux;
- } {
- {alpha=beta"gamma} * 1 1 {alpha=beta"gamma} 0 1 1
- {delta[epsilon]zeta} * 1 1 {delta[epsilon]zeta} 0 1 1
- }
-
- do_execsql_test 9.$tn.4 {
- CREATE VIRTUAL TABLE t7aux USING fts4aux(t7);
- INSERT INTO t7 VALUES('alephxbeth\xC4gimel');
- SELECT * FROM t7aux;
- } {
- aleph * 1 1 aleph 0 1 1
- beth * 1 1 beth 0 1 1
- gimel * 1 1 gimel 0 1 1
- }
-}
-
-# Check that multiple options are handled correctly.
-#
-do_execsql_test 10.1 {
- DROP TABLE IF EXISTS t1;
- CREATE VIRTUAL TABLE t1 USING fts4(tokenize=unicode61
- "tokenchars=xyz" "tokenchars=.=" "separators=.=" "separators=xy"
- "separators=a" "separators=a" "tokenchars=a" "tokenchars=a"
- );
-
- INSERT INTO t1 VALUES('oneatwoxthreeyfour');
- INSERT INTO t1 VALUES('a.single=word');
- CREATE VIRTUAL TABLE t1aux USING fts4aux(t1);
- SELECT * FROM t1aux;
-} {
- .single=word * 1 1 .single=word 0 1 1
- four * 1 1 four 0 1 1
- one * 1 1 one 0 1 1
- three * 1 1 three 0 1 1
- two * 1 1 two 0 1 1
-}
-
-# Test that case folding happens after tokenization, not before.
-#
-do_execsql_test 10.2 {
- DROP TABLE IF EXISTS t2;
- CREATE VIRTUAL TABLE t2 USING fts4(tokenize=unicode61 "separators=aB");
- INSERT INTO t2 VALUES('oneatwoBthree');
- INSERT INTO t2 VALUES('onebtwoAthree');
- CREATE VIRTUAL TABLE t2aux USING fts4aux(t2);
- SELECT * FROM t2aux;
-} {
- one * 1 1 one 0 1 1
- onebtwoathree * 1 1 onebtwoathree 0 1 1
- three * 1 1 three 0 1 1
- two * 1 1 two 0 1 1
-}
-# Test that the tokenchars and separators options work with the
-# fts3tokenize table.
-#
-do_execsql_test 11.1 {
- CREATE VIRTUAL TABLE ft1 USING fts3tokenize(
- "unicode61", "tokenchars=@.", "separators=1234567890"
- );
- SELECT token FROM ft1 WHERE input = 'berlin@street123sydney.road';
+foreach {tn val bErr} {
+ 1 0 0
+ 2 1 0
+ 3 2 0
+ 4 3 1
+ 5 11 1
} {
- berlin@street sydney.road
-}
-
+ reset_db
+ set aRes(0) {0 {}}
+ set aRes(1) {1 {error in tokenizer constructor}}
+ set res $aRes($bErr)
+ do_catchsql_test 9.1.$tn "
+ CREATE VIRTUAL TABLE bl USING fts5(
+ s, tokenize='trigram remove_diacritics $val'
+ );
+ " $res
}
finish_test
diff --git a/ext/fts5/test/fts5unicode3.test b/ext/fts5/test/fts5unicode3.test
index 30eb3c4166..ddb61a9997 100644
--- a/ext/fts5/test/fts5unicode3.test
+++ b/ext/fts5/test/fts5unicode3.test
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5unicode4.test b/ext/fts5/test/fts5unicode4.test
index dfd7f5a254..dc225cb5e2 100644
--- a/ext/fts5/test/fts5unicode4.test
+++ b/ext/fts5/test/fts5unicode4.test
@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5unicode4
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5unindexed.test b/ext/fts5/test/fts5unindexed.test
index 8b72c4c776..5099a89693 100644
--- a/ext/fts5/test/fts5unindexed.test
+++ b/ext/fts5/test/fts5unindexed.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5unindexed
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
diff --git a/ext/fts5/test/fts5unindexed2.test b/ext/fts5/test/fts5unindexed2.test
new file mode 100644
index 0000000000..c0abfc3980
--- /dev/null
+++ b/ext/fts5/test/fts5unindexed2.test
@@ -0,0 +1,297 @@
+# 2024 Sep 13
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# The tests in this file focus on "unindexed" columns in contentless
+# tables.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5unindexed2
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+
+do_execsql_test 1.1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(
+ a, b UNINDEXED, content=, contentless_unindexed=1
+ );
+} {}
+
+do_execsql_test 1.2 {
+ INSERT INTO t1 VALUES('abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.3 {
+ SELECT rowid, a, b FROM t1
+} {1 {} {ghi jkl}}
+
+do_execsql_test 1.4 {
+ INSERT INTO t1(rowid, a, b) VALUES(11, 'hello world', 'one two three');
+}
+
+do_execsql_test 1.5 {
+ INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 1, 'abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.6 {
+ SELECT rowid, a, b FROM t1
+} {
+ 11 {} {one two three}
+}
+
+do_execsql_test 1.7 {
+ PRAGMA integrity_check
+} {ok}
+
+do_execsql_test 1.8 {
+ INSERT INTO t1(rowid, a, b) VALUES(12, 'abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.9 {
+ SELECT rowid, a, b FROM t1('def')
+} {12 {} {ghi jkl}}
+
+do_execsql_test 1.10 {
+ SELECT rowid, a, b FROM t1('def OR hello') ORDER BY rank
+} {11 {} {one two three} 12 {} {ghi jkl}}
+
+do_execsql_test 1.11 {
+ SELECT rowid, a, b FROM t1 WHERE rowid=11
+} {11 {} {one two three}}
+
+do_execsql_test 1.12 {
+ SELECT rowid, a, b FROM t1
+} {11 {} {one two three} 12 {} {ghi jkl}}
+
+
+fts5_aux_test_functions db
+do_execsql_test 1.12.2 {
+ SELECT rowid, fts5_test_columntext(t1) FROM t1('def OR hello')
+} {11 {{} {one two three}} 12 {{} {ghi jkl}}}
+
+do_execsql_test 1.13 {
+ INSERT INTO t1(t1) VALUES('delete-all');
+}
+
+do_execsql_test 1.14 {
+ SELECT rowid, a, b FROM t1
+}
+
+do_execsql_test 1.15 {
+ PRAGMA integrity_check
+} {ok}
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE t4 USING fts5(
+ x, y UNINDEXED, z, columnsize=0, content='', contentless_unindexed=1
+ );
+}
+
+do_execsql_test 2.1 {
+ INSERT INTO t4(rowid, x, y, z) VALUES(1, 'a a', 'b b b', 'c');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(
+ a UNINDEXED, b, c UNINDEXED, d, content=, contentless_delete=1,
+ contentless_unindexed=1
+ );
+}
+
+do_execsql_test 3.1 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(131, 'aaa', 'bbb', 'ccc', 'ddd');
+}
+
+do_execsql_test 3.2 {
+ SELECT * FROM x1
+} {aaa {} ccc {}}
+
+do_execsql_test 3.3 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(1000, 'AAA', 'BBB', 'CCC', 'DDD');
+}
+
+do_execsql_test 3.4 {
+ SELECT rowid, * FROM x1
+} {
+ 131 aaa {} ccc {}
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.5 {
+ DELETE FROM x1 WHERE rowid=131;
+ SELECT rowid, * FROM x1
+} {
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.6 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(112, 'aaa', 'bbb', 'ccc', 'ddd');
+ SELECT rowid, * FROM x1
+} {
+ 112 aaa {} ccc {}
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.7 {
+ UPDATE x1 SET b='hello', d='world', rowid=1120 WHERE rowid=112
+}
+
+do_execsql_test 3.8 {
+ SELECT rowid, * FROM x1
+} {
+ 1000 AAA {} CCC {}
+ 1120 aaa {} ccc {}
+}
+
+do_execsql_test 3.9 {
+ SELECT rowid, * FROM x1('hello');
+} {
+ 1120 aaa {} ccc {}
+}
+
+do_execsql_test 3.9 {
+ SELECT rowid, * FROM x1('bbb');
+} {
+ 1000 AAA {} CCC {}
+}
+
+fts5_aux_test_functions db
+do_execsql_test 3.10 {
+ SELECT rowid, fts5_test_columntext(x1) FROM x1('b*')
+} {1000 {AAA {} CCC {}}}
+
+#-------------------------------------------------------------------------
+# Check that if contentless_unindexed=1 is not specified, the values
+# of UNINDEXED columns are not stored in the database.
+#
+# Also check that contentless_unindexed=1 is not allowed unless the table
+# is actually contentless.
+#
+reset_db
+do_execsql_test 4.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(a, b, c UNINDEXED, content='');
+ INSERT INTO ft VALUES('one', 'two', 'three');
+ SELECT rowid, * FROM ft;
+} {1 {} {} {}}
+
+do_execsql_test 4.1 {
+ SELECT name FROM sqlite_schema ORDER BY 1
+} {
+ ft ft_config ft_data ft_docsize ft_idx
+}
+
+do_catchsql_test 4.2 {
+ CREATE VIRTUAL TABLE ft2 USING fts5(
+ a, b, c UNINDEXED, contentless_unindexed=1
+ );
+} {1 {contentless_unindexed=1 requires a contentless table}}
+
+do_catchsql_test 4.3 {
+ DELETE FROM ft WHERE rowid=1
+} {1 {cannot DELETE from contentless fts5 table: ft}}
+
+#-------------------------------------------------------------------------
+# Check that the usual restrictions on contentless tables apply to
+# contentless_unindexed=1 tables.
+#
+reset_db
+do_execsql_test 5.0 {
+ CREATE VIRTUAL TABLE ft USING fts5(
+ a, b UNINDEXED, c, content='', contentless_unindexed=1
+ );
+ INSERT INTO ft VALUES('one', 'two', 'three');
+ INSERT INTO ft VALUES('four', 'five', 'six');
+ INSERT INTO ft VALUES('seven', 'eight', 'nine');
+ SELECT rowid, * FROM ft;
+} {
+ 1 {} two {}
+ 2 {} five {}
+ 3 {} eight {}
+}
+
+do_execsql_test 5.1 {
+ PRAGMA integrity_check
+} {ok}
+
+do_catchsql_test 5.2 {
+ DELETE FROM ft WHERE rowid=2
+} {1 {cannot DELETE from contentless fts5 table: ft}}
+
+do_execsql_test 5.3 {
+ SELECT rowid, * FROM ft('six')
+} {
+ 2 {} five {}
+}
+
+do_catchsql_test 5.4 {
+ UPDATE ft SET a='x', b='y', c='z' WHERE rowid=3
+} {1 {cannot UPDATE contentless fts5 table: ft}}
+
+fts5_aux_test_functions db
+
+do_execsql_test 5.5 {
+ SELECT fts5_test_columntext(ft) FROM ft WHERE rowid=3
+} {
+ {{} eight {}}
+}
+do_execsql_test 5.6 {
+ SELECT fts5_test_columntext(ft) FROM ft('three');
+} {
+ {{} two {}}
+}
+
+#-------------------------------------------------------------------------
+# Check that it is possible to UPDATE a contentless_unindexed=1 table
+# if the only columns being modified are UNINDEXED.
+#
+# If the contentless_unindexed=1 table is also contentless_delete=1, then
+# it is also possible to update indexed columns - but only if *all* indexed
+# columns are updated.
+#
+reset_db
+do_execsql_test 6.0 {
+ CREATE VIRTUAL TABLE ft1 USING fts5(a, b UNINDEXED, c UNINDEXED, d,
+ contentless_unindexed=1, content=''
+ );
+
+ INSERT INTO ft1(rowid, a, b, c, d) VALUES
+ (100, 'x y', 'b1', 'c1', 'a b'),
+ (200, 'c d', 'b2', 'c2', 'a b'),
+ (300, 'e f', 'b3', 'c3', 'a b');
+}
+
+do_execsql_test 6.1 {
+ UPDATE ft1 SET b='b1.1', c='c1.1' WHERE rowid=100;
+}
+do_execsql_test 6.2 {
+ UPDATE ft1 SET b='b2.1' WHERE rowid=200;
+}
+do_execsql_test 6.3 {
+ UPDATE ft1 SET c='c3.1' WHERE rowid=300;
+}
+
+do_execsql_test 6.4 {
+ SELECT rowid, a, b, c, d FROM ft1
+} {
+ 100 {} b1.1 c1.1 {}
+ 200 {} b2.1 c2 {}
+ 300 {} b3 c3.1 {}
+}
+
+finish_test
+
diff --git a/ext/fts5/test/fts5update2.test b/ext/fts5/test/fts5update2.test
new file mode 100644
index 0000000000..d04af4800d
--- /dev/null
+++ b/ext/fts5/test/fts5update2.test
@@ -0,0 +1,177 @@
+# 2024 Sep 27
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this script is testing the FTS5 module.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5update2
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+
+#-------------------------------------------------------------------------
+# Test that the various types of UPDATE statement are handled correctly
+# by different table types.
+#
+foreach_detail_mode $testprefix {
+foreach {tn cu} {
+ 1 0
+ 2 1
+} {
+ reset_db
+ do_execsql_test 1.$tn.1 "
+ CREATE VIRTUAL TABLE ft1 USING fts5(a, b UNINDEXED, c UNINDEXED, d,
+ content='',
+ contentless_unindexed=$cu,
+ detail=%DETAIL%
+ );
+ CREATE VIRTUAL TABLE ft2 USING fts5(a, b UNINDEXED, c UNINDEXED, d,
+ content='',
+ contentless_unindexed=$cu, contentless_delete=1,
+ detail=%DETAIL%
+ );
+ "
+
+ do_execsql_test 1.$tn.2 {
+ INSERT INTO ft1(rowid, a, b, c, d) VALUES(1, 'a1', 'b1', 'c1', 'd1');
+ INSERT INTO ft1(rowid, a, b, c, d) VALUES(2, 'a2', 'b2', 'c2', 'd2');
+ INSERT INTO ft1(rowid, a, b, c, d) VALUES(3, 'a3', 'b3', 'c3', 'd3');
+
+ INSERT INTO ft2(rowid, a, b, c, d) VALUES(1, 'a1', 'b1', 'c1', 'd1');
+ INSERT INTO ft2(rowid, a, b, c, d) VALUES(2, 'a2', 'b2', 'c2', 'd2');
+ INSERT INTO ft2(rowid, a, b, c, d) VALUES(3, 'a3', 'b3', 'c3', 'd3');
+ }
+
+ # It should be possible to update a subset of the UNINDEXED columns of
+ # a contentless table. Regardless of whether or not contentless_unindexed=1
+ # or contentless_delete=1 is set.
+ do_execsql_test 1.$tn.3 {
+ UPDATE ft1 SET b=b||'.1';
+ UPDATE ft2 SET b=b||'.1';
+ }
+ do_execsql_test 1.$tn.4 {
+ UPDATE ft1 SET b=b||'.2', c=c||'.2';
+ UPDATE ft2 SET b=b||'.2', c=c||'.2';
+ }
+
+ set res(0) {
+ 1 {} {} {} {}
+ 2 {} {} {} {}
+ 3 {} {} {} {}
+ }
+ set res(1) {
+ 1 {} b1.1.2 c1.2 {}
+ 2 {} b2.1.2 c2.2 {}
+ 3 {} b3.1.2 c3.2 {}
+ }
+
+ do_execsql_test 1.$tn.5 {
+ SELECT rowid, * FROM ft2
+ } $res($cu)
+
+ do_execsql_test 1.6.1 { SELECT rowid FROM ft1('a2') } {2}
+ do_execsql_test 1.6.2 { SELECT rowid FROM ft2('a2') } {2}
+
+ # It should be possible to update all indexed columns (but no other subset)
+ # if the contentless_delete=1 option is set, as it is for "ft2".
+ do_execsql_test 1.$tn.7 {
+ UPDATE ft2 SET a='a22', d='d22' WHERE rowid=2;
+ }
+ do_execsql_test 1.$tn.8 { SELECT rowid FROM ft2('a22 AND d22') } {2}
+
+ do_execsql_test 1.$tn.9 {
+ UPDATE ft2 SET a='a33', d='d33', b='b3' WHERE rowid=3;
+ }
+
+ set res(1) {
+ 1 {} b1.1.2 c1.2 {}
+ 2 {} b2.1.2 c2.2 {}
+ 3 {} b3 c3.2 {}
+ }
+ do_execsql_test 1.$tn.10 {
+ SELECT rowid, * FROM ft2
+ } $res($cu)
+
+ do_catchsql_test 1.$tn.11 {
+ UPDATE ft2 SET a='a11' WHERE rowid=1
+ } {1 {cannot UPDATE a subset of columns on fts5 contentless-delete table: ft2}}
+ do_catchsql_test 1.$tn.12 {
+ UPDATE ft2 SET d='d11' WHERE rowid=1
+ } {1 {cannot UPDATE a subset of columns on fts5 contentless-delete table: ft2}}
+
+ # It is not possible to update the values of indexed columns if
+ # contentless_delete=1 is not set.
+ do_catchsql_test 1.$tn.13 {
+ UPDATE ft1 SET a='a11' WHERE rowid=1
+ } {1 {cannot UPDATE contentless fts5 table: ft1}}
+ do_catchsql_test 1.$tn.14 {
+ UPDATE ft1 SET d='d11' WHERE rowid=1
+ } {1 {cannot UPDATE contentless fts5 table: ft1}}
+
+ # It should be possible to update the rowid if contentless_delete=1 is
+ # set and all indexed columns are updated.
+ do_execsql_test 1.$tn.15 {
+ UPDATE ft2 SET a='aXone', d='dXone', rowid=11 WHERE rowid=1
+ }
+
+ set res(0) {
+ 2 {} {} {} {}
+ 3 {} {} {} {}
+ 11 {} {} {} {}
+ }
+ set res(1) {
+ 2 {} b2.1.2 c2.2 {}
+ 3 {} b3 c3.2 {}
+ 11 {} b1.1.2 c1.2 {}
+ }
+ do_execsql_test 1.$tn.16 {
+ SELECT rowid, * FROM ft2
+ } $res($cu)
+
+ # Should not be possible to update the rowid of a contentless_delete=1
+ # table if no indexed columns are updated.
+ do_catchsql_test 1.$tn.17 {
+ UPDATE ft2 SET rowid=12 WHERE rowid=11
+ } {1 {cannot UPDATE a subset of columns on fts5 contentless-delete table: ft2}}
+ do_catchsql_test 1.$tn.18 {
+ UPDATE ft1 SET rowid=12 WHERE rowid=1
+ } {1 {cannot UPDATE contentless fts5 table: ft1}}
+
+ do_execsql_test 1.$tn.19 {
+ UPDATE ft2 SET a='aXtwo', d='dXtwo', c='newval', rowid=12 WHERE rowid=2
+ } {}
+
+ set res(0) {
+ 3 {} {} {} {}
+ 11 {} {} {} {}
+ 12 {} {} {} {}
+ }
+ set res(1) {
+ 3 {} b3 c3.2 {}
+ 11 {} b1.1.2 c1.2 {}
+ 12 {} b2.1.2 newval {}
+ }
+ do_execsql_test 1.$tn.20 {
+ SELECT rowid, * FROM ft2
+ } $res($cu)
+
+ do_execsql_test 1.$tn.21 {
+ SELECT rowid, * FROM ft2('aXtwo AND dXtwo')
+ } [lrange $res($cu) 10 end]
+
+}} ;# end of [foreach_detail_mode] loop
+
+finish_test
diff --git a/ext/fts5/test/fts5version.test b/ext/fts5/test/fts5version.test
index 79fd94e6bc..58dd9fe14e 100644
--- a/ext/fts5/test/fts5version.test
+++ b/ext/fts5/test/fts5version.test
@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5version
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -112,7 +112,7 @@ do_execsql_test 2.1 {
do_execsql_test 2.2 {
SELECT v FROM xyz_config WHERE k='version';
-} {5}
+} {4}
do_execsql_test 2.3 {
ROLLBACK TO one;
diff --git a/ext/fts5/test/fts5vocab.test b/ext/fts5/test/fts5vocab.test
index c457c5c210..b1644527ea 100644
--- a/ext/fts5/test/fts5vocab.test
+++ b/ext/fts5/test/fts5vocab.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5vocab
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -513,6 +513,7 @@ do_execsql_test 10.5 {
INSERT INTO ft(a) VALUES('4 5 6');
}
+unset -nocomplain x res
do_test 10.6 {
set res [list]
db eval { SELECT rowid FROM ft('4') } x {
diff --git a/ext/fts5/test/fts5vocab2.test b/ext/fts5/test/fts5vocab2.test
index 6f7aad329c..7b3c3b0d6a 100644
--- a/ext/fts5/test/fts5vocab2.test
+++ b/ext/fts5/test/fts5vocab2.test
@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5vocab2
-# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
@@ -280,6 +280,30 @@ do_catchsql_test 5.2 {
INSERT INTO t1 SELECT randomblob(3000) FROM v1
} {1 {query aborted}}
+#-------------------------------------------------------------------------
+reset_db
+sqlite3_fts5_may_be_corrupt 1
+
+do_execsql_test 6.0 {
+ BEGIN TRANSACTION;
+ CREATE VIRTUAL TABLE t1 USING fts5(a,b unindexed,c,tokenize="porter ascii",tokendata=1);
+ REPLACE INTO t1_data VALUES(1,X'03090009');
+ REPLACE INTO t1_data VALUES(10,X'000000000103030003010101020101030101');
+ REPLACE INTO t1_data VALUES(137438953473,X'0000002e023061010202010162010203010163010204010167010601020201016801060102030101690106010204040606060808');
+ REPLACE INTO t1_data VALUES(274877906945,X'0000001f013067020802010202010168020803010203010169020804010204040909');
+ REPLACE INTO t1_data VALUES(412316860417,X'0000002e023061030202010162030203010163030204010167030601020201016803060102030101690306010204040606060808');
+ COMMIT;
+}
+
+do_execsql_test 6.1 {
+ CREATE VIRTUAL TABLE t3 USING fts5vocab('t1', 'row');
+}
+
+do_catchsql_test 6.2 {
+ SELECT * FROM t3;
+} {1 {database disk image is malformed}}
+
+sqlite3_fts5_may_be_corrupt 0
finish_test
diff --git a/ext/fts5/tool/mkfts5c.tcl b/ext/fts5/tool/mkfts5c.tcl
index b1a55fa4ae..6f20a0cd73 100644
--- a/ext/fts5/tool/mkfts5c.tcl
+++ b/ext/fts5/tool/mkfts5c.tcl
@@ -2,7 +2,7 @@
# restart with tclsh \
exec tclsh "$0" "$@"
-set srcdir [file dirname [file dirname [info script]]]
+set srcdir [file dirname [file dirname [file normalize [info script]]]]
set G(src) [string map [list %dir% $srcdir] {
%dir%/fts5.h
%dir%/fts5Int.h
@@ -23,7 +23,27 @@ set G(src) [string map [list %dir% $srcdir] {
}]
set G(hdr) {
-
+/*
+** This, the "fts5.c" source file, is a composite file that is itself
+** assembled from the following files:
+**
+** fts5.h
+** fts5Int.h
+** fts5parse.h <--- Generated from fts5parse.y by Lemon
+** fts5parse.c <--- Generated from fts5parse.y by Lemon
+** fts5_aux.c
+** fts5_buffer.c
+** fts5_config.c
+** fts5_expr.c
+** fts5_hash.c
+** fts5_index.c
+** fts5_main.c
+** fts5_storage.c
+** fts5_tokenize.c
+** fts5_unicode2.c
+** fts5_varint.c
+** fts5_vocab.c
+*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
@@ -33,10 +53,16 @@ set G(hdr) {
# undef NDEBUG
#endif
+#ifdef HAVE_STDINT_H
+#include
+#endif
+#ifdef HAVE_INTTYPES_H
+#include
+#endif
}
set G(footer) {
-
+/* Here ends the fts5.c composite file. */
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
}
diff --git a/ext/icu/README.txt b/ext/icu/README.txt
index c3c35a2c6f..40def24662 100644
--- a/ext/icu/README.txt
+++ b/ext/icu/README.txt
@@ -1,19 +1,18 @@
-
This directory contains source code for the SQLite "ICU" extension, an
integration of the "International Components for Unicode" library with
SQLite. Documentation follows.
1. Features
-
+
1.1 SQL Scalars upper() and lower()
1.2 Unicode Aware LIKE Operator
1.3 ICU Collation Sequences
1.4 SQL REGEXP Operator
-
+
2. Compilation and Usage
-
+
3. Bugs, Problems and Security Issues
-
+
3.1 The "case_sensitive_like" Pragma
3.2 The SQLITE_MAX_LIKE_PATTERN_LENGTH Macro
3.3 Collation Sequence Security Issue
@@ -23,10 +22,10 @@ SQLite. Documentation follows.
1.1 SQL Scalars upper() and lower()
- SQLite's built-in implementations of these two functions only
+ SQLite's built-in implementations of these two functions only
provide case mapping for the 26 letters used in the English
language. The ICU based functions provided by this extension
- provide case mapping, where defined, for the full range of
+ provide case mapping, where defined, for the full range of
unicode characters.
ICU provides two types of case mapping, "general" case mapping and
@@ -36,7 +35,7 @@ SQLite. Documentation follows.
http://www.icu-project.org/userguide/caseMappings.html
http://www.icu-project.org/userguide/posix.html#case_mappings
- To utilise "general" case mapping, the upper() or lower() scalar
+ To utilise "general" case mapping, the upper() or lower() scalar
functions are invoked with one argument:
upper('abc') -> 'ABC'
@@ -57,7 +56,7 @@ SQLite. Documentation follows.
operator understands case equivalence for the 26 letters of the English
language alphabet. The implementation of LIKE included in this
extension uses the ICU function u_foldCase() to provide case
- independent comparisons for the full range of unicode characters.
+ independent comparisons for the full range of unicode characters.
The U_FOLD_CASE_DEFAULT flag is passed to u_foldCase(), meaning the
dotless 'I' character used in the Turkish language is considered
@@ -66,9 +65,9 @@ SQLite. Documentation follows.
1.3 ICU Collation Sequences
- A special SQL scalar function, icu_load_collation() is provided that
+ A special SQL scalar function, icu_load_collation() is provided that
may be used to register ICU collation sequences with SQLite. It
- is always called with exactly two arguments, the ICU locale
+ is always called with exactly two arguments, the ICU locale
identifying the collation sequence to ICU, and the name of the
SQLite collation sequence to create. For example, to create an
SQLite collation sequence named "turkish" using Turkish language
@@ -87,7 +86,7 @@ SQLite. Documentation follows.
australian_penpal_name TEXT COLLATE australian,
turkish_penpal_name TEXT COLLATE turkish
);
-
+
1.4 SQL REGEXP Operator
This extension provides an implementation of the SQL binary
@@ -116,7 +115,7 @@ SQLite. Documentation follows.
and use it as a dynamically loadable SQLite extension. To do this
using gcc on *nix:
- gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-uc icu-io` \
+ gcc -fPIC -shared icu.c `pkg-config --libs --cflags icu-io` \
-o libSqliteIcu.so
You may need to add "-I" flags so that gcc can find sqlite3ext.h
@@ -124,6 +123,11 @@ SQLite. Documentation follows.
loaded into sqlite in the same way as any other dynamically loadable
extension.
+ As of version 3.48, it can be enabled in the canonical build process
+ by passing one of --with-icu-config or --with-icu-ldflags to the
+ configure script, optionally together with --enable-icu-collations.
+ See the configure --help for more details.
+
3 BUGS, PROBLEMS AND SECURITY ISSUES
@@ -144,13 +148,13 @@ SQLite. Documentation follows.
SQLITE_MAX_LIKE_PATTERN_LENGTH macro as the maximum length of a
pattern in bytes (irrespective of encoding). The default value is
defined in internal header file "limits.h".
-
- The ICU extension LIKE implementation suffers from the same
+
+ The ICU extension LIKE implementation suffers from the same
problem and uses the same solution. However, since the ICU extension
code does not include the SQLite file "limits.h", modifying
the default value therein does not affect the ICU extension.
The default value of SQLITE_MAX_LIKE_PATTERN_LENGTH used by
- the ICU extension LIKE operator is 50000, defined in source
+ the ICU extension LIKE operator is 50000, defined in source
file "icu.c".
3.3 Collation Sequence Security
diff --git a/ext/icu/icu.c b/ext/icu/icu.c
index e745ab0253..50110072b5 100644
--- a/ext/icu/icu.c
+++ b/ext/icu/icu.c
@@ -471,7 +471,7 @@ static void icuLoadCollation(
UCollator *pUCollator; /* ICU library collation object */
int rc; /* Return code from sqlite3_create_collation_x() */
- assert(nArg==2);
+ assert(nArg==2 || nArg==3);
(void)nArg; /* Unused parameter */
zLocale = (const char *)sqlite3_value_text(apArg[0]);
zName = (const char *)sqlite3_value_text(apArg[1]);
@@ -486,7 +486,39 @@ static void icuLoadCollation(
return;
}
assert(p);
-
+ if(nArg==3){
+ const char *zOption = (const char*)sqlite3_value_text(apArg[2]);
+ static const struct {
+ const char *zName;
+ UColAttributeValue val;
+ } aStrength[] = {
+ { "PRIMARY", UCOL_PRIMARY },
+ { "SECONDARY", UCOL_SECONDARY },
+ { "TERTIARY", UCOL_TERTIARY },
+ { "DEFAULT", UCOL_DEFAULT_STRENGTH },
+ { "QUARTERNARY", UCOL_QUATERNARY },
+ { "IDENTICAL", UCOL_IDENTICAL },
+ };
+ unsigned int i;
+ for(i=0; i=sizeof(aStrength)/sizeof(aStrength[0]) ){
+ sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p));
+ sqlite3_str_appendf(pStr,
+ "unknown collation strength \"%s\" - should be one of:",
+ zOption);
+ for(i=0; i
+#include
+
+#include
+#include
+
+/*
+** nKeyVal:
+** The number of values that make up the 'key' for the current pCheck
+** statement.
+**
+** rc:
+** Error code returned by most recent sqlite3_intck_step() or
+** sqlite3_intck_unlock() call. This is set to SQLITE_DONE when
+** the integrity-check operation is finished.
+**
+** zErr:
+** If the object has entered the error state, this is the error message.
+** Is freed using sqlite3_free() when the object is deleted.
+**
+** zTestSql:
+** The value returned by the most recent call to sqlite3_intck_testsql().
+** Each call to testsql() frees the previous zTestSql value (using
+** sqlite3_free()) and replaces it with the new value it will return.
+*/
+struct sqlite3_intck {
+ sqlite3 *db;
+ const char *zDb; /* Copy of zDb parameter to _open() */
+ char *zObj; /* Current object. Or NULL. */
+
+ sqlite3_stmt *pCheck; /* Current check statement */
+ char *zKey;
+ int nKeyVal;
+
+ char *zMessage;
+ int bCorruptSchema;
+
+ int rc; /* Error code */
+ char *zErr; /* Error message */
+ char *zTestSql; /* Returned by sqlite3_intck_test_sql() */
+};
+
+
+/*
+** Some error has occurred while using database p->db. Save the error message
+** and error code currently held by the database handle in p->rc and p->zErr.
+*/
+static void intckSaveErrmsg(sqlite3_intck *p){
+ p->rc = sqlite3_errcode(p->db);
+ sqlite3_free(p->zErr);
+ p->zErr = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
+}
+
+/*
+** If the handle passed as the first argument is already in the error state,
+** then this function is a no-op (returns NULL immediately). Otherwise, if an
+** error occurs within this function, it leaves an error in said handle.
+**
+** Otherwise, this function attempts to prepare SQL statement zSql and
+** return the resulting statement handle to the user.
+*/
+static sqlite3_stmt *intckPrepare(sqlite3_intck *p, const char *zSql){
+ sqlite3_stmt *pRet = 0;
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3_prepare_v2(p->db, zSql, -1, &pRet, 0);
+ if( p->rc!=SQLITE_OK ){
+ intckSaveErrmsg(p);
+ assert( pRet==0 );
+ }
+ }
+ return pRet;
+}
+
+/*
+** If the handle passed as the first argument is already in the error state,
+** then this function is a no-op (returns NULL immediately). Otherwise, if an
+** error occurs within this function, it leaves an error in said handle.
+**
+** Otherwise, this function treats argument zFmt as a printf() style format
+** string. It formats it according to the trailing arguments and then
+** attempts to prepare the results and return the resulting prepared
+** statement.
+*/
+static sqlite3_stmt *intckPrepareFmt(sqlite3_intck *p, const char *zFmt, ...){
+ sqlite3_stmt *pRet = 0;
+ va_list ap;
+ char *zSql = 0;
+ va_start(ap, zFmt);
+ zSql = sqlite3_vmprintf(zFmt, ap);
+ if( p->rc==SQLITE_OK && zSql==0 ){
+ p->rc = SQLITE_NOMEM;
+ }
+ pRet = intckPrepare(p, zSql);
+ sqlite3_free(zSql);
+ va_end(ap);
+ return pRet;
+}
+
+/*
+** Finalize SQL statement pStmt. If an error occurs and the handle passed
+** as the first argument does not already contain an error, store the
+** error in the handle.
+*/
+static void intckFinalize(sqlite3_intck *p, sqlite3_stmt *pStmt){
+ int rc = sqlite3_finalize(pStmt);
+ if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){
+ intckSaveErrmsg(p);
+ }
+}
+
+/*
+** If there is already an error in handle p, return it. Otherwise, call
+** sqlite3_step() on the statement handle and return that value.
+*/
+static int intckStep(sqlite3_intck *p, sqlite3_stmt *pStmt){
+ if( p->rc ) return p->rc;
+ return sqlite3_step(pStmt);
+}
+
+/*
+** Execute SQL statement zSql. There is no way to obtain any results
+** returned by the statement. This function uses the sqlite3_intck error
+** code convention.
+*/
+static void intckExec(sqlite3_intck *p, const char *zSql){
+ sqlite3_stmt *pStmt = 0;
+ pStmt = intckPrepare(p, zSql);
+ intckStep(p, pStmt);
+ intckFinalize(p, pStmt);
+}
+
+/*
+** A wrapper around sqlite3_mprintf() that uses the sqlite3_intck error
+** code convention.
+*/
+static char *intckMprintf(sqlite3_intck *p, const char *zFmt, ...){
+ va_list ap;
+ char *zRet = 0;
+ va_start(ap, zFmt);
+ zRet = sqlite3_vmprintf(zFmt, ap);
+ if( p->rc==SQLITE_OK ){
+ if( zRet==0 ){
+ p->rc = SQLITE_NOMEM;
+ }
+ }else{
+ sqlite3_free(zRet);
+ zRet = 0;
+ }
+ return zRet;
+}
+
+/*
+** This is used by sqlite3_intck_unlock() to save the vector key value
+** required to restart the current pCheck query as a nul-terminated string
+** in p->zKey.
+*/
+static void intckSaveKey(sqlite3_intck *p){
+ int ii;
+ char *zSql = 0;
+ sqlite3_stmt *pStmt = 0;
+ sqlite3_stmt *pXinfo = 0;
+ const char *zDir = 0;
+
+ assert( p->pCheck );
+ assert( p->zKey==0 );
+
+ pXinfo = intckPrepareFmt(p,
+ "SELECT group_concat(desc, '') FROM %Q.sqlite_schema s, "
+ "pragma_index_xinfo(%Q, %Q) "
+ "WHERE s.type='index' AND s.name=%Q",
+ p->zDb, p->zObj, p->zDb, p->zObj
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXinfo) ){
+ zDir = (const char*)sqlite3_column_text(pXinfo, 0);
+ }
+
+ if( zDir==0 ){
+ /* Object is a table, not an index. This is the easy case,as there are
+ ** no DESC columns or NULL values in a primary key. */
+ const char *zSep = "SELECT '(' || ";
+ for(ii=0; iinKeyVal; ii++){
+ zSql = intckMprintf(p, "%z%squote(?)", zSql, zSep);
+ zSep = " || ', ' || ";
+ }
+ zSql = intckMprintf(p, "%z || ')'", zSql);
+ }else{
+
+ /* Object is an index. */
+ assert( p->nKeyVal>1 );
+ for(ii=p->nKeyVal; ii>0; ii--){
+ int bLastIsDesc = zDir[ii-1]=='1';
+ int bLastIsNull = sqlite3_column_type(p->pCheck, ii)==SQLITE_NULL;
+ const char *zLast = sqlite3_column_name(p->pCheck, ii);
+ char *zLhs = 0;
+ char *zRhs = 0;
+ char *zWhere = 0;
+
+ if( bLastIsNull ){
+ if( bLastIsDesc ) continue;
+ zWhere = intckMprintf(p, "'%s IS NOT NULL'", zLast);
+ }else{
+ const char *zOp = bLastIsDesc ? "<" : ">";
+ zWhere = intckMprintf(p, "'%s %s ' || quote(?%d)", zLast, zOp, ii);
+ }
+
+ if( ii>1 ){
+ const char *zLhsSep = "";
+ const char *zRhsSep = "";
+ int jj;
+ for(jj=0; jjpCheck,jj+1);
+ zLhs = intckMprintf(p, "%z%s%s", zLhs, zLhsSep, zAlias);
+ zRhs = intckMprintf(p, "%z%squote(?%d)", zRhs, zRhsSep, jj+1);
+ zLhsSep = ",";
+ zRhsSep = " || ',' || ";
+ }
+
+ zWhere = intckMprintf(p,
+ "'(%z) IS (' || %z || ') AND ' || %z",
+ zLhs, zRhs, zWhere);
+ }
+ zWhere = intckMprintf(p, "'WHERE ' || %z", zWhere);
+
+ zSql = intckMprintf(p, "%z%s(quote( %z ) )",
+ zSql,
+ (zSql==0 ? "VALUES" : ",\n "),
+ zWhere
+ );
+ }
+ zSql = intckMprintf(p,
+ "WITH wc(q) AS (\n%z\n)"
+ "SELECT 'VALUES' || group_concat('(' || q || ')', ',\n ') FROM wc"
+ , zSql
+ );
+ }
+
+ pStmt = intckPrepare(p, zSql);
+ if( p->rc==SQLITE_OK ){
+ for(ii=0; iinKeyVal; ii++){
+ sqlite3_bind_value(pStmt, ii+1, sqlite3_column_value(p->pCheck, ii+1));
+ }
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ p->zKey = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
+ }
+ intckFinalize(p, pStmt);
+ }
+
+ sqlite3_free(zSql);
+ intckFinalize(p, pXinfo);
+}
+
+/*
+** Find the next database object (table or index) to check. If successful,
+** set sqlite3_intck.zObj to point to a nul-terminated buffer containing
+** the object's name before returning.
+*/
+static void intckFindObject(sqlite3_intck *p){
+ sqlite3_stmt *pStmt = 0;
+ char *zPrev = p->zObj;
+ p->zObj = 0;
+
+ assert( p->rc==SQLITE_OK );
+ assert( p->pCheck==0 );
+
+ pStmt = intckPrepareFmt(p,
+ "WITH tables(table_name) AS ("
+ " SELECT name"
+ " FROM %Q.sqlite_schema WHERE (type='table' OR type='index') AND rootpage"
+ " UNION ALL "
+ " SELECT 'sqlite_schema'"
+ ")"
+ "SELECT table_name FROM tables "
+ "WHERE ?1 IS NULL OR table_name%s?1 "
+ "ORDER BY 1"
+ , p->zDb, (p->zKey ? ">=" : ">")
+ );
+
+ if( p->rc==SQLITE_OK ){
+ sqlite3_bind_text(pStmt, 1, zPrev, -1, SQLITE_TRANSIENT);
+ if( sqlite3_step(pStmt)==SQLITE_ROW ){
+ p->zObj = intckMprintf(p,"%s",(const char*)sqlite3_column_text(pStmt, 0));
+ }
+ }
+ intckFinalize(p, pStmt);
+
+ /* If this is a new object, ensure the previous key value is cleared. */
+ if( sqlite3_stricmp(p->zObj, zPrev) ){
+ sqlite3_free(p->zKey);
+ p->zKey = 0;
+ }
+
+ sqlite3_free(zPrev);
+}
+
+/*
+** Return the size in bytes of the first token in nul-terminated buffer z.
+** For the purposes of this call, a token is either:
+**
+** * a quoted SQL string,
+* * a contiguous series of ascii alphabet characters, or
+* * any other single byte.
+*/
+static int intckGetToken(const char *z){
+ char c = z[0];
+ int iRet = 1;
+ if( c=='\'' || c=='"' || c=='`' ){
+ while( 1 ){
+ if( z[iRet]==c ){
+ iRet++;
+ if( z[iRet]!=c ) break;
+ }
+ iRet++;
+ }
+ }
+ else if( c=='[' ){
+ while( z[iRet++]!=']' && z[iRet] );
+ }
+ else if( (c>='A' && c<='Z') || (c>='a' && c<='z') ){
+ while( (z[iRet]>='A' && z[iRet]<='Z') || (z[iRet]>='a' && z[iRet]<='z') ){
+ iRet++;
+ }
+ }
+
+ return iRet;
+}
+
+/*
+** Return true if argument c is an ascii whitespace character.
+*/
+static int intckIsSpace(char c){
+ return (c==' ' || c=='\t' || c=='\n' || c=='\r');
+}
+
+/*
+** Argument z points to the text of a CREATE INDEX statement. This function
+** identifies the part of the text that contains either the index WHERE
+** clause (if iCol<0) or the iCol'th column of the index.
+**
+** If (iCol<0), the identified fragment does not include the "WHERE" keyword,
+** only the expression that follows it. If (iCol>=0) then the identified
+** fragment does not include any trailing sort-order keywords - "ASC" or
+** "DESC".
+**
+** If the CREATE INDEX statement does not contain the requested field or
+** clause, NULL is returned and (*pnByte) is set to 0. Otherwise, a pointer to
+** the identified fragment is returned and output parameter (*pnByte) set
+** to its size in bytes.
+*/
+static const char *intckParseCreateIndex(const char *z, int iCol, int *pnByte){
+ int iOff = 0;
+ int iThisCol = 0;
+ int iStart = 0;
+ int nOpen = 0;
+
+ const char *zRet = 0;
+ int nRet = 0;
+
+ int iEndOfCol = 0;
+
+ /* Skip forward until the first "(" token */
+ while( z[iOff]!='(' ){
+ iOff += intckGetToken(&z[iOff]);
+ if( z[iOff]=='\0' ) return 0;
+ }
+ assert( z[iOff]=='(' );
+
+ nOpen = 1;
+ iOff++;
+ iStart = iOff;
+ while( z[iOff] ){
+ const char *zToken = &z[iOff];
+ int nToken = 0;
+
+ /* Check if this is the end of the current column - either a "," or ")"
+ ** when nOpen==1. */
+ if( nOpen==1 ){
+ if( z[iOff]==',' || z[iOff]==')' ){
+ if( iCol==iThisCol ){
+ int iEnd = iEndOfCol ? iEndOfCol : iOff;
+ nRet = (iEnd - iStart);
+ zRet = &z[iStart];
+ break;
+ }
+ iStart = iOff+1;
+ while( intckIsSpace(z[iStart]) ) iStart++;
+ iThisCol++;
+ }
+ if( z[iOff]==')' ) break;
+ }
+ if( z[iOff]=='(' ) nOpen++;
+ if( z[iOff]==')' ) nOpen--;
+ nToken = intckGetToken(zToken);
+
+ if( (nToken==3 && 0==sqlite3_strnicmp(zToken, "ASC", nToken))
+ || (nToken==4 && 0==sqlite3_strnicmp(zToken, "DESC", nToken))
+ ){
+ iEndOfCol = iOff;
+ }else if( 0==intckIsSpace(zToken[0]) ){
+ iEndOfCol = 0;
+ }
+
+ iOff += nToken;
+ }
+
+ /* iStart is now the byte offset of 1 byte passed the final ')' in the
+ ** CREATE INDEX statement. Try to find a WHERE clause to return. */
+ while( zRet==0 && z[iOff] ){
+ int n = intckGetToken(&z[iOff]);
+ if( n==5 && 0==sqlite3_strnicmp(&z[iOff], "where", 5) ){
+ zRet = &z[iOff+5];
+ nRet = (int)strlen(zRet);
+ }
+ iOff += n;
+ }
+
+ /* Trim any whitespace from the start and end of the returned string. */
+ if( zRet ){
+ while( intckIsSpace(zRet[0]) ){
+ nRet--;
+ zRet++;
+ }
+ while( nRet>0 && intckIsSpace(zRet[nRet-1]) ) nRet--;
+ }
+
+ *pnByte = nRet;
+ return zRet;
+}
+
+/*
+** User-defined SQL function wrapper for intckParseCreateIndex():
+**
+** SELECT parse_create_index(, );
+*/
+static void intckParseCreateIndexFunc(
+ sqlite3_context *pCtx,
+ int nVal,
+ sqlite3_value **apVal
+){
+ const char *zSql = (const char*)sqlite3_value_text(apVal[0]);
+ int idx = sqlite3_value_int(apVal[1]);
+ const char *zRes = 0;
+ int nRes = 0;
+
+ assert( nVal==2 );
+ if( zSql ){
+ zRes = intckParseCreateIndex(zSql, idx, &nRes);
+ }
+ sqlite3_result_text(pCtx, zRes, nRes, SQLITE_TRANSIENT);
+}
+
+/*
+** Return true if sqlite3_intck.db has automatic indexes enabled, false
+** otherwise.
+*/
+static int intckGetAutoIndex(sqlite3_intck *p){
+ int bRet = 0;
+ sqlite3_stmt *pStmt = 0;
+ pStmt = intckPrepare(p, "PRAGMA automatic_index");
+ if( SQLITE_ROW==intckStep(p, pStmt) ){
+ bRet = sqlite3_column_int(pStmt, 0);
+ }
+ intckFinalize(p, pStmt);
+ return bRet;
+}
+
+/*
+** Return true if zObj is an index, or false otherwise.
+*/
+static int intckIsIndex(sqlite3_intck *p, const char *zObj){
+ int bRet = 0;
+ sqlite3_stmt *pStmt = 0;
+ pStmt = intckPrepareFmt(p,
+ "SELECT 1 FROM %Q.sqlite_schema WHERE name=%Q AND type='index'",
+ p->zDb, zObj
+ );
+ if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ bRet = 1;
+ }
+ intckFinalize(p, pStmt);
+ return bRet;
+}
+
+/*
+** Return a pointer to a nul-terminated buffer containing the SQL statement
+** used to check database object zObj (a table or index) for corruption.
+** If parameter zPrev is not NULL, then it must be a string containing the
+** vector key required to restart the check where it left off last time.
+** If pnKeyVal is not NULL, then (*pnKeyVal) is set to the number of
+** columns in the vector key value for the specified object.
+**
+** This function uses the sqlite3_intck error code convention.
+*/
+static char *intckCheckObjectSql(
+ sqlite3_intck *p, /* Integrity check object */
+ const char *zObj, /* Object (table or index) to scan */
+ const char *zPrev, /* Restart key vector, if any */
+ int *pnKeyVal /* OUT: Number of key-values for this scan */
+){
+ char *zRet = 0;
+ sqlite3_stmt *pStmt = 0;
+ int bAutoIndex = 0;
+ int bIsIndex = 0;
+
+ const char *zCommon =
+ /* Relation without_rowid also contains just one row. Column "b" is
+ ** set to true if the table being examined is a WITHOUT ROWID table,
+ ** or false otherwise. */
+ ", without_rowid(b) AS ("
+ " SELECT EXISTS ("
+ " SELECT 1 FROM tabname, pragma_index_list(tab, db) AS l"
+ " WHERE origin='pk' "
+ " AND NOT EXISTS (SELECT 1 FROM sqlite_schema WHERE name=l.name)"
+ " )"
+ ")"
+ ""
+ /* Table idx_cols contains 1 row for each column in each index on the
+ ** table being checked. Columns are:
+ **
+ ** idx_name: Name of the index.
+ ** idx_ispk: True if this index is the PK of a WITHOUT ROWID table.
+ ** col_name: Name of indexed column, or NULL for index on expression.
+ ** col_expr: Indexed expression, including COLLATE clause.
+ ** col_alias: Alias used for column in 'intck_wrapper' table.
+ */
+ ", idx_cols(idx_name, idx_ispk, col_name, col_expr, col_alias) AS ("
+ " SELECT l.name, (l.origin=='pk' AND w.b), i.name, COALESCE(("
+ " SELECT parse_create_index(sql, i.seqno) FROM "
+ " sqlite_schema WHERE name = l.name"
+ " ), format('\"%w\"', i.name) || ' COLLATE ' || quote(i.coll)),"
+ " 'c' || row_number() OVER ()"
+ " FROM "
+ " tabname t,"
+ " without_rowid w,"
+ " pragma_index_list(t.tab, t.db) l,"
+ " pragma_index_xinfo(l.name) i"
+ " WHERE i.key"
+ " UNION ALL"
+ " SELECT '', 1, '_rowid_', '_rowid_', 'r1' FROM without_rowid WHERE b=0"
+ ")"
+ ""
+ ""
+ /*
+ ** For a PK declared as "PRIMARY KEY(a, b) ... WITHOUT ROWID", where
+ ** the intck_wrapper aliases of "a" and "b" are "c1" and "c2":
+ **
+ ** o_pk: "o.c1, o.c2"
+ ** i_pk: "i.'a', i.'b'"
+ ** ...
+ ** n_pk: 2
+ */
+ ", tabpk(db, tab, idx, o_pk, i_pk, q_pk, eq_pk, ps_pk, pk_pk, n_pk) AS ("
+ " WITH pkfields(f, a) AS ("
+ " SELECT i.col_name, i.col_alias FROM idx_cols i WHERE i.idx_ispk"
+ " )"
+ " SELECT t.db, t.tab, t.idx, "
+ " group_concat(a, ', '), "
+ " group_concat('i.'||quote(f), ', '), "
+ " group_concat('quote(o.'||a||')', ' || '','' || '), "
+ " format('(%s)==(%s)',"
+ " group_concat('o.'||a, ', '), "
+ " group_concat(format('\"%w\"', f), ', ')"
+ " ),"
+ " group_concat('%s', ','),"
+ " group_concat('quote('||a||')', ', '), "
+ " count(*)"
+ " FROM tabname t, pkfields"
+ ")"
+ ""
+ ", idx(name, match_expr, partial, partial_alias, idx_ps, idx_idx) AS ("
+ " SELECT idx_name,"
+ " format('(%s,%s) IS (%s,%s)', "
+ " group_concat(i.col_expr, ', '), i_pk,"
+ " group_concat('o.'||i.col_alias, ', '), o_pk"
+ " ), "
+ " parse_create_index("
+ " (SELECT sql FROM sqlite_schema WHERE name=idx_name), -1"
+ " ),"
+ " 'cond' || row_number() OVER ()"
+ " , group_concat('%s', ',')"
+ " , group_concat('quote('||i.col_alias||')', ', ')"
+ " FROM tabpk t, "
+ " without_rowid w,"
+ " idx_cols i"
+ " WHERE i.idx_ispk==0 "
+ " GROUP BY idx_name"
+ ")"
+ ""
+ ", wrapper_with(s) AS ("
+ " SELECT 'intck_wrapper AS (\n SELECT\n ' || ("
+ " WITH f(a, b) AS ("
+ " SELECT col_expr, col_alias FROM idx_cols"
+ " UNION ALL "
+ " SELECT partial, partial_alias FROM idx WHERE partial IS NOT NULL"
+ " )"
+ " SELECT group_concat(format('%s AS %s', a, b), ',\n ') FROM f"
+ " )"
+ " || format('\n FROM %Q.%Q ', t.db, t.tab)"
+ /* If the object being checked is a table, append "NOT INDEXED".
+ ** Otherwise, append "INDEXED BY ", and then, if the index
+ ** is a partial index " WHERE ". */
+ " || CASE WHEN t.idx IS NULL THEN "
+ " 'NOT INDEXED'"
+ " ELSE"
+ " format('INDEXED BY %Q%s', t.idx, ' WHERE '||i.partial)"
+ " END"
+ " || '\n)'"
+ " FROM tabname t LEFT JOIN idx i ON (i.name=t.idx)"
+ ")"
+ ""
+ ;
+
+ bAutoIndex = intckGetAutoIndex(p);
+ if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 0");
+
+ bIsIndex = intckIsIndex(p, zObj);
+ if( bIsIndex ){
+ pStmt = intckPrepareFmt(p,
+ /* Table idxname contains a single row. The first column, "db", contains
+ ** the name of the db containing the table (e.g. "main") and the second,
+ ** "tab", the name of the table itself. */
+ "WITH tabname(db, tab, idx) AS ("
+ " SELECT %Q, (SELECT tbl_name FROM %Q.sqlite_schema WHERE name=%Q), %Q "
+ ")"
+ ""
+ ", whereclause(w_c) AS (%s)"
+ ""
+ "%s" /* zCommon */
+ ""
+ ", case_statement(c) AS ("
+ " SELECT "
+ " 'CASE WHEN (' || group_concat(col_alias, ', ') || ', 1) IS (\n' "
+ " || ' SELECT ' || group_concat(col_expr, ', ') || ', 1 FROM '"
+ " || format('%%Q.%%Q NOT INDEXED WHERE %%s\n', t.db, t.tab, p.eq_pk)"
+ " || ' )\n THEN NULL\n '"
+ " || 'ELSE format(''surplus entry ('"
+ " || group_concat('%%s', ',') || ',' || p.ps_pk"
+ " || ') in index ' || t.idx || ''', ' "
+ " || group_concat('quote('||i.col_alias||')', ', ') || ', ' || p.pk_pk"
+ " || ')'"
+ " || '\n END AS error_message'"
+ " FROM tabname t, tabpk p, idx_cols i WHERE i.idx_name=t.idx"
+ ")"
+ ""
+ ", thiskey(k, n) AS ("
+ " SELECT group_concat(i.col_alias, ', ') || ', ' || p.o_pk, "
+ " count(*) + p.n_pk "
+ " FROM tabpk p, idx_cols i WHERE i.idx_name=p.idx"
+ ")"
+ ""
+ ", main_select(m, n) AS ("
+ " SELECT format("
+ " 'WITH %%s\n' ||"
+ " ', idx_checker AS (\n' ||"
+ " ' SELECT %%s,\n' ||"
+ " ' %%s\n' || "
+ " ' FROM intck_wrapper AS o\n' ||"
+ " ')\n',"
+ " ww.s, c, t.k"
+ " ), t.n"
+ " FROM case_statement, wrapper_with ww, thiskey t"
+ ")"
+
+ "SELECT m || "
+ " group_concat('SELECT * FROM idx_checker ' || w_c, ' UNION ALL '), n"
+ " FROM "
+ "main_select, whereclause "
+ , p->zDb, p->zDb, zObj, zObj
+ , zPrev ? zPrev : "VALUES('')", zCommon
+ );
+ }else{
+ pStmt = intckPrepareFmt(p,
+ /* Table tabname contains a single row. The first column, "db", contains
+ ** the name of the db containing the table (e.g. "main") and the second,
+ ** "tab", the name of the table itself. */
+ "WITH tabname(db, tab, idx, prev) AS (SELECT %Q, %Q, NULL, %Q)"
+ ""
+ "%s" /* zCommon */
+
+ /* expr(e) contains one row for each index on table zObj. Value e
+ ** is set to an expression that evaluates to NULL if the required
+ ** entry is present in the index, or an error message otherwise. */
+ ", expr(e, p) AS ("
+ " SELECT format('CASE WHEN EXISTS \n"
+ " (SELECT 1 FROM %%Q.%%Q AS i INDEXED BY %%Q WHERE %%s%%s)\n"
+ " THEN NULL\n"
+ " ELSE format(''entry (%%s,%%s) missing from index %%s'', %%s, %%s)\n"
+ " END\n'"
+ " , t.db, t.tab, i.name, i.match_expr, ' AND (' || partial || ')',"
+ " i.idx_ps, t.ps_pk, i.name, i.idx_idx, t.pk_pk),"
+ " CASE WHEN partial IS NULL THEN NULL ELSE i.partial_alias END"
+ " FROM tabpk t, idx i"
+ ")"
+
+ ", numbered(ii, cond, e) AS ("
+ " SELECT 0, 'n.ii=0', 'NULL'"
+ " UNION ALL "
+ " SELECT row_number() OVER (),"
+ " '(n.ii='||row_number() OVER ()||COALESCE(' AND '||p||')', ')'), e"
+ " FROM expr"
+ ")"
+
+ ", counter_with(w) AS ("
+ " SELECT 'WITH intck_counter(ii) AS (\n ' || "
+ " group_concat('SELECT '||ii, ' UNION ALL\n ') "
+ " || '\n)' FROM numbered"
+ ")"
+ ""
+ ", case_statement(c) AS ("
+ " SELECT 'CASE ' || "
+ " group_concat(format('\n WHEN %%s THEN (%%s)', cond, e), '') ||"
+ " '\nEND AS error_message'"
+ " FROM numbered"
+ ")"
+ ""
+
+ /* This table contains a single row consisting of a single value -
+ ** the text of an SQL expression that may be used by the main SQL
+ ** statement to output an SQL literal that can be used to resume
+ ** the scan if it is suspended. e.g. for a rowid table, an expression
+ ** like:
+ **
+ ** format('(%d,%d)', _rowid_, n.ii)
+ */
+ ", thiskey(k, n) AS ("
+ " SELECT o_pk || ', ii', n_pk+1 FROM tabpk"
+ ")"
+ ""
+ ", whereclause(w_c) AS ("
+ " SELECT CASE WHEN prev!='' THEN "
+ " '\nWHERE (' || o_pk ||', n.ii) > ' || prev"
+ " ELSE ''"
+ " END"
+ " FROM tabpk, tabname"
+ ")"
+ ""
+ ", main_select(m, n) AS ("
+ " SELECT format("
+ " '%%s, %%s\nSELECT %%s,\n%%s\nFROM intck_wrapper AS o"
+ ", intck_counter AS n%%s\nORDER BY %%s', "
+ " w, ww.s, c, thiskey.k, whereclause.w_c, t.o_pk"
+ " ), thiskey.n"
+ " FROM case_statement, tabpk t, counter_with, "
+ " wrapper_with ww, thiskey, whereclause"
+ ")"
+
+ "SELECT m, n FROM main_select",
+ p->zDb, zObj, zPrev, zCommon
+ );
+ }
+
+ while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ zRet = intckMprintf(p, "%s", (const char*)sqlite3_column_text(pStmt, 0));
+ if( pnKeyVal ){
+ *pnKeyVal = sqlite3_column_int(pStmt, 1);
+ }
+ }
+ intckFinalize(p, pStmt);
+
+ if( bAutoIndex ) intckExec(p, "PRAGMA automatic_index = 1");
+ return zRet;
+}
+
+/*
+** Open a new integrity-check object.
+*/
+int sqlite3_intck_open(
+ sqlite3 *db, /* Database handle to operate on */
+ const char *zDbArg, /* "main", "temp" etc. */
+ sqlite3_intck **ppOut /* OUT: New integrity-check handle */
+){
+ sqlite3_intck *pNew = 0;
+ int rc = SQLITE_OK;
+ const char *zDb = zDbArg ? zDbArg : "main";
+ int nDb = (int)strlen(zDb);
+
+ pNew = (sqlite3_intck*)sqlite3_malloc(sizeof(*pNew) + nDb + 1);
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, sizeof(*pNew));
+ pNew->db = db;
+ pNew->zDb = (const char*)&pNew[1];
+ memcpy(&pNew[1], zDb, nDb+1);
+ rc = sqlite3_create_function(db, "parse_create_index",
+ 2, SQLITE_UTF8, 0, intckParseCreateIndexFunc, 0, 0
+ );
+ if( rc!=SQLITE_OK ){
+ sqlite3_intck_close(pNew);
+ pNew = 0;
+ }
+ }
+
+ *ppOut = pNew;
+ return rc;
+}
+
+/*
+** Free the integrity-check object.
+*/
+void sqlite3_intck_close(sqlite3_intck *p){
+ if( p ){
+ sqlite3_finalize(p->pCheck);
+ sqlite3_create_function(
+ p->db, "parse_create_index", 1, SQLITE_UTF8, 0, 0, 0, 0
+ );
+ sqlite3_free(p->zObj);
+ sqlite3_free(p->zKey);
+ sqlite3_free(p->zTestSql);
+ sqlite3_free(p->zErr);
+ sqlite3_free(p->zMessage);
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Step the integrity-check object.
+*/
+int sqlite3_intck_step(sqlite3_intck *p){
+ if( p->rc==SQLITE_OK ){
+
+ if( p->zMessage ){
+ sqlite3_free(p->zMessage);
+ p->zMessage = 0;
+ }
+
+ if( p->bCorruptSchema ){
+ p->rc = SQLITE_DONE;
+ }else
+ if( p->pCheck==0 ){
+ intckFindObject(p);
+ if( p->rc==SQLITE_OK ){
+ if( p->zObj ){
+ char *zSql = 0;
+ zSql = intckCheckObjectSql(p, p->zObj, p->zKey, &p->nKeyVal);
+ p->pCheck = intckPrepare(p, zSql);
+ sqlite3_free(zSql);
+ sqlite3_free(p->zKey);
+ p->zKey = 0;
+ }else{
+ p->rc = SQLITE_DONE;
+ }
+ }else if( p->rc==SQLITE_CORRUPT ){
+ p->rc = SQLITE_OK;
+ p->zMessage = intckMprintf(p, "%s",
+ "corruption found while reading database schema"
+ );
+ p->bCorruptSchema = 1;
+ }
+ }
+
+ if( p->pCheck ){
+ assert( p->rc==SQLITE_OK );
+ if( sqlite3_step(p->pCheck)==SQLITE_ROW ){
+ /* Normal case, do nothing. */
+ }else{
+ intckFinalize(p, p->pCheck);
+ p->pCheck = 0;
+ p->nKeyVal = 0;
+ if( p->rc==SQLITE_CORRUPT ){
+ p->rc = SQLITE_OK;
+ p->zMessage = intckMprintf(p,
+ "corruption found while scanning database object %s", p->zObj
+ );
+ }
+ }
+ }
+ }
+
+ return p->rc;
+}
+
+/*
+** Return a message describing the corruption encountered by the most recent
+** call to sqlite3_intck_step(), or NULL if no corruption was encountered.
+*/
+const char *sqlite3_intck_message(sqlite3_intck *p){
+ assert( p->pCheck==0 || p->zMessage==0 );
+ if( p->zMessage ){
+ return p->zMessage;
+ }
+ if( p->pCheck ){
+ return (const char*)sqlite3_column_text(p->pCheck, 0);
+ }
+ return 0;
+}
+
+/*
+** Return the error code and message.
+*/
+int sqlite3_intck_error(sqlite3_intck *p, const char **pzErr){
+ if( pzErr ) *pzErr = p->zErr;
+ return (p->rc==SQLITE_DONE ? SQLITE_OK : p->rc);
+}
+
+/*
+** Close any read transaction the integrity-check object is holding open
+** on the database.
+*/
+int sqlite3_intck_unlock(sqlite3_intck *p){
+ if( p->rc==SQLITE_OK && p->pCheck ){
+ assert( p->zKey==0 && p->nKeyVal>0 );
+ intckSaveKey(p);
+ intckFinalize(p, p->pCheck);
+ p->pCheck = 0;
+ }
+ return p->rc;
+}
+
+/*
+** Return the SQL statement used to check object zObj. Or, if zObj is
+** NULL, the current SQL statement.
+*/
+const char *sqlite3_intck_test_sql(sqlite3_intck *p, const char *zObj){
+ sqlite3_free(p->zTestSql);
+ if( zObj ){
+ p->zTestSql = intckCheckObjectSql(p, zObj, 0, 0);
+ }else{
+ if( p->zObj ){
+ p->zTestSql = intckCheckObjectSql(p, p->zObj, p->zKey, 0);
+ }else{
+ sqlite3_free(p->zTestSql);
+ p->zTestSql = 0;
+ }
+ }
+ return p->zTestSql;
+}
diff --git a/ext/intck/sqlite3intck.h b/ext/intck/sqlite3intck.h
new file mode 100644
index 0000000000..e08a86f289
--- /dev/null
+++ b/ext/intck/sqlite3intck.h
@@ -0,0 +1,171 @@
+/*
+** 2024-02-08
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+*/
+
+/*
+** Incremental Integrity-Check Extension
+** -------------------------------------
+**
+** This module contains code to check whether or not an SQLite database
+** is well-formed or corrupt. This is the same task as performed by SQLite's
+** built-in "PRAGMA integrity_check" command. This module differs from
+** "PRAGMA integrity_check" in that:
+**
+** + It is less thorough - this module does not detect certain types
+** of corruption that are detected by the PRAGMA command. However,
+** it does detect all kinds of corruption that are likely to cause
+** errors in SQLite applications.
+**
+** + It is slower. Sometimes up to three times slower.
+**
+** + It allows integrity-check operations to be split into multiple
+** transactions, so that the database does not need to be read-locked
+** for the duration of the integrity-check.
+**
+** One way to use the API to run integrity-check on the "main" database
+** of handle db is:
+**
+** int rc = SQLITE_OK;
+** sqlite3_intck *p = 0;
+**
+** sqlite3_intck_open(db, "main", &p);
+** while( SQLITE_OK==sqlite3_intck_step(p) ){
+** const char *zMsg = sqlite3_intck_message(p);
+** if( zMsg ) printf("corruption: %s\n", zMsg);
+** }
+** rc = sqlite3_intck_error(p, &zErr);
+** if( rc!=SQLITE_OK ){
+** printf("error occured (rc=%d), (errmsg=%s)\n", rc, zErr);
+** }
+** sqlite3_intck_close(p);
+**
+** Usually, the sqlite3_intck object opens a read transaction within the
+** first call to sqlite3_intck_step() and holds it open until the
+** integrity-check is complete. However, if sqlite3_intck_unlock() is
+** called, the read transaction is ended and a new read transaction opened
+** by the subsequent call to sqlite3_intck_step().
+*/
+
+#ifndef _SQLITE_INTCK_H
+#define _SQLITE_INTCK_H
+
+#include "sqlite3.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** An ongoing incremental integrity-check operation is represented by an
+** opaque pointer of the following type.
+*/
+typedef struct sqlite3_intck sqlite3_intck;
+
+/*
+** Open a new incremental integrity-check object. If successful, populate
+** output variable (*ppOut) with the new object handle and return SQLITE_OK.
+** Or, if an error occurs, set (*ppOut) to NULL and return an SQLite error
+** code (e.g. SQLITE_NOMEM).
+**
+** The integrity-check will be conducted on database zDb (which must be "main",
+** "temp", or the name of an attached database) of database handle db. Once
+** this function has been called successfully, the caller should not use
+** database handle db until the integrity-check object has been destroyed
+** using sqlite3_intck_close().
+*/
+int sqlite3_intck_open(
+ sqlite3 *db, /* Database handle */
+ const char *zDb, /* Database name ("main", "temp" etc.) */
+ sqlite3_intck **ppOut /* OUT: New sqlite3_intck handle */
+);
+
+/*
+** Close and release all resources associated with a handle opened by an
+** earlier call to sqlite3_intck_open(). The results of using an
+** integrity-check handle after it has been passed to this function are
+** undefined.
+*/
+void sqlite3_intck_close(sqlite3_intck *pCk);
+
+/*
+** Do the next step of the integrity-check operation specified by the handle
+** passed as the only argument. This function returns SQLITE_DONE if the
+** integrity-check operation is finished, or an SQLite error code if
+** an error occurs, or SQLITE_OK if no error occurs but the integrity-check
+** is not finished. It is not considered an error if database corruption
+** is encountered.
+**
+** Following a successful call to sqlite3_intck_step() (one that returns
+** SQLITE_OK), sqlite3_intck_message() returns a non-NULL value if
+** corruption was detected in the db.
+**
+** If an error occurs and a value other than SQLITE_OK or SQLITE_DONE is
+** returned, then the integrity-check handle is placed in an error state.
+** In this state all subsequent calls to sqlite3_intck_step() or
+** sqlite3_intck_unlock() will immediately return the same error. The
+** sqlite3_intck_error() method may be used to obtain an English language
+** error message in this case.
+*/
+int sqlite3_intck_step(sqlite3_intck *pCk);
+
+/*
+** If the previous call to sqlite3_intck_step() encountered corruption
+** within the database, then this function returns a pointer to a buffer
+** containing a nul-terminated string describing the corruption in
+** English. If the previous call to sqlite3_intck_step() did not encounter
+** corruption, or if there was no previous call, this function returns
+** NULL.
+*/
+const char *sqlite3_intck_message(sqlite3_intck *pCk);
+
+/*
+** Close any read-transaction opened by an earlier call to
+** sqlite3_intck_step(). Any subsequent call to sqlite3_intck_step() will
+** open a new transaction. Return SQLITE_OK if successful, or an SQLite error
+** code otherwise.
+**
+** If an error occurs, then the integrity-check handle is placed in an error
+** state. In this state all subsequent calls to sqlite3_intck_step() or
+** sqlite3_intck_unlock() will immediately return the same error. The
+** sqlite3_intck_error() method may be used to obtain an English language
+** error message in this case.
+*/
+int sqlite3_intck_unlock(sqlite3_intck *pCk);
+
+/*
+** If an error has occurred in an earlier call to sqlite3_intck_step()
+** or sqlite3_intck_unlock(), then this method returns the associated
+** SQLite error code. Additionally, if pzErr is not NULL, then (*pzErr)
+** may be set to point to a nul-terminated string containing an English
+** language error message. Or, if no error message is available, to
+** NULL.
+**
+** If no error has occurred within sqlite3_intck_step() or
+** sqlite_intck_unlock() calls on the handle passed as the first argument,
+** then SQLITE_OK is returned and (*pzErr) set to NULL.
+*/
+int sqlite3_intck_error(sqlite3_intck *pCk, const char **pzErr);
+
+/*
+** This API is used for testing only. It returns the full-text of an SQL
+** statement used to test object zObj, which may be a table or index.
+** The returned buffer is valid until the next call to either this function
+** or sqlite3_intck_close() on the same sqlite3_intck handle.
+*/
+const char *sqlite3_intck_test_sql(sqlite3_intck *pCk, const char *zObj);
+
+
+#ifdef __cplusplus
+} /* end of the 'extern "C"' block */
+#endif
+
+#endif /* ifndef _SQLITE_INTCK_H */
diff --git a/ext/intck/test_intck.c b/ext/intck/test_intck.c
new file mode 100644
index 0000000000..d3a619b503
--- /dev/null
+++ b/ext/intck/test_intck.c
@@ -0,0 +1,233 @@
+/*
+** 2010 August 28
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Code for testing all sorts of SQLite interfaces. This code
+** is not included in the SQLite library.
+*/
+
+#include "sqlite3.h"
+#include "sqlite3intck.h"
+#include "tclsqlite.h"
+#include
+#include
+
+/* In test1.c */
+int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
+const char *sqlite3ErrName(int);
+
+typedef struct TestIntck TestIntck;
+struct TestIntck {
+ sqlite3_intck *intck;
+};
+
+static int testIntckCmd(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ struct Subcmd {
+ const char *zName;
+ int nArg;
+ const char *zExpect;
+ } aCmd[] = {
+ {"close", 0, ""}, /* 0 */
+ {"step", 0, ""}, /* 1 */
+ {"message", 0, ""}, /* 2 */
+ {"error", 0, ""}, /* 3 */
+ {"unlock", 0, ""}, /* 4 */
+ {"test_sql", 1, ""}, /* 5 */
+ {0 , 0}
+ };
+ int rc = TCL_OK;
+ int iIdx = -1;
+ TestIntck *p = (TestIntck*)clientData;
+
+ if( objc<2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
+ return TCL_ERROR;
+ }
+
+ rc = Tcl_GetIndexFromObjStruct(
+ interp, objv[1], aCmd, sizeof(aCmd[0]), "SUB-COMMAND", 0, &iIdx
+ );
+ if( rc ) return rc;
+
+ if( objc!=2+aCmd[iIdx].nArg ){
+ Tcl_WrongNumArgs(interp, 2, objv, aCmd[iIdx].zExpect);
+ return TCL_ERROR;
+ }
+
+ switch( iIdx ){
+ case 0: assert( 0==strcmp("close", aCmd[iIdx].zName) ); {
+ Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
+ break;
+ }
+
+ case 1: assert( 0==strcmp("step", aCmd[iIdx].zName) ); {
+ rc = sqlite3_intck_step(p->intck);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ break;
+ }
+
+ case 2: assert( 0==strcmp("message", aCmd[iIdx].zName) ); {
+ const char *z = sqlite3_intck_message(p->intck);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(z ? z : "", -1));
+ break;
+ }
+
+ case 3: assert( 0==strcmp("error", aCmd[iIdx].zName) ); {
+ const char *zErr = 0;
+ Tcl_Obj *pRes;
+ rc = sqlite3_intck_error(p->intck, 0);
+ pRes = Tcl_NewObj();
+ Tcl_ListObjAppendElement(
+ interp, pRes, Tcl_NewStringObj(sqlite3ErrName(rc), -1)
+ );
+ sqlite3_intck_error(p->intck, &zErr);
+ Tcl_ListObjAppendElement(
+ interp, pRes, Tcl_NewStringObj(zErr ? zErr : 0, -1)
+ );
+ Tcl_SetObjResult(interp, pRes);
+ break;
+ }
+
+ case 4: assert( 0==strcmp("unlock", aCmd[iIdx].zName) ); {
+ rc = sqlite3_intck_unlock(p->intck);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ break;
+ }
+
+ case 5: assert( 0==strcmp("test_sql", aCmd[iIdx].zName) ); {
+ const char *zObj = Tcl_GetString(objv[2]);
+ const char *zSql = sqlite3_intck_test_sql(p->intck, zObj[0] ? zObj : 0);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(zSql, -1));
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+/*
+** Destructor for commands created by test_sqlite3_intck().
+*/
+static void testIntckFree(void *clientData){
+ TestIntck *p = (TestIntck*)clientData;
+ sqlite3_intck_close(p->intck);
+ ckfree(p);
+}
+
+/*
+** tclcmd: sqlite3_intck DB DBNAME
+*/
+static int test_sqlite3_intck(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ char zName[64];
+ int iName = 0;
+ Tcl_CmdInfo info;
+ TestIntck *p = 0;
+ sqlite3 *db = 0;
+ const char *zDb = 0;
+ int rc = SQLITE_OK;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
+ return TCL_ERROR;
+ }
+
+ p = (TestIntck*)ckalloc(sizeof(TestIntck));
+ memset(p, 0, sizeof(TestIntck));
+
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+ return TCL_ERROR;
+ }
+ zDb = Tcl_GetString(objv[2]);
+ if( zDb[0]=='\0' ) zDb = 0;
+
+ rc = sqlite3_intck_open(db, zDb, &p->intck);
+ if( rc!=SQLITE_OK ){
+ ckfree(p);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errstr(rc), -1));
+ return TCL_ERROR;
+ }
+
+ do {
+ sprintf(zName, "intck%d", iName++);
+ }while( Tcl_GetCommandInfo(interp, zName, &info)!=0 );
+ Tcl_CreateObjCommand(interp, zName, testIntckCmd, (void*)p, testIntckFree);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(zName, -1));
+
+ return TCL_OK;
+}
+
+/*
+** tclcmd: test_do_intck DB DBNAME
+*/
+static int test_do_intck(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db = 0;
+ const char *zDb = 0;
+ int rc = SQLITE_OK;
+ sqlite3_intck *pCk = 0;
+ Tcl_Obj *pRet = 0;
+ const char *zErr = 0;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
+ return TCL_ERROR;
+ }
+ zDb = Tcl_GetString(objv[2]);
+
+ pRet = Tcl_NewObj();
+ Tcl_IncrRefCount(pRet);
+
+ rc = sqlite3_intck_open(db, zDb, &pCk);
+ if( rc==SQLITE_OK ){
+ while( sqlite3_intck_step(pCk)==SQLITE_OK ){
+ const char *zMsg = sqlite3_intck_message(pCk);
+ if( zMsg ){
+ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zMsg, -1));
+ }
+ }
+ rc = sqlite3_intck_error(pCk, &zErr);
+ }
+ if( rc!=SQLITE_OK ){
+ if( zErr ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
+ }else{
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ }
+ }else{
+ Tcl_SetObjResult(interp, pRet);
+ }
+ Tcl_DecrRefCount(pRet);
+ sqlite3_intck_close(pCk);
+ sqlite3_intck_close(0);
+ return rc ? TCL_ERROR : TCL_OK;
+}
+
+int Sqlitetestintck_Init(Tcl_Interp *interp){
+ Tcl_CreateObjCommand(interp, "sqlite3_intck", test_sqlite3_intck, 0, 0);
+ Tcl_CreateObjCommand(interp, "test_do_intck", test_do_intck, 0, 0);
+ return TCL_OK;
+}
diff --git a/ext/jni/GNUmakefile b/ext/jni/GNUmakefile
index 19a5080471..26a38dad9a 100644
--- a/ext/jni/GNUmakefile
+++ b/ext/jni/GNUmakefile
@@ -35,6 +35,8 @@ $(dir.bld.c):
javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?=
+javac.flags += -encoding utf8
+# -------------^^^^^^^^^^^^^^ required for Windows builds
jnicheck ?= 1
ifeq (1,$(jnicheck))
java.flags += -Xcheck:jni
@@ -79,6 +81,7 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
# Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae.
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
+ Experimental.java \
NotNull.java \
Nullable.java \
) $(patsubst %,$(dir.src.capi)/%,\
@@ -91,7 +94,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
CollationNeededCallback.java \
CommitHookCallback.java \
ConfigLogCallback.java \
- ConfigSqllogCallback.java \
+ ConfigSqlLogCallback.java \
NativePointerHolder.java \
OutputPointer.java \
PrepareMultiCallback.java \
@@ -110,6 +113,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
WindowFunction.java \
XDestroyCallback.java \
sqlite3.java \
+ sqlite3_blob.java \
sqlite3_context.java \
sqlite3_stmt.java \
sqlite3_value.java \
@@ -120,6 +124,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
Sqlite.java \
SqliteException.java \
ValueHolder.java \
+ WindowFunction.java \
)
JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
@@ -159,12 +164,13 @@ endif
CLASS_FILES :=
define CLASSFILE_DEPS
all: $(1).class
+$(1).class: $(1).java
CLASS_FILES += $(1).class
endef
$(foreach B,$(basename \
$(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.tester)),\
$(eval $(call CLASSFILE_DEPS,$(B))))
-$(CLASS_FILES): $(JAVA_FILES) $(MAKEFILE)
+$(CLASS_FILES): $(MAKEFILE)
$(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)
#.PHONY: classfiles
@@ -226,7 +232,8 @@ SQLITE_OPT += -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_OFFSET_SQL_FUNC \
-DSQLITE_ENABLE_PREUPDATE_HOOK \
-DSQLITE_ENABLE_NORMALIZE \
- -DSQLITE_ENABLE_SQLLOG
+ -DSQLITE_ENABLE_SQLLOG \
+ -DSQLITE_ENABLE_COLUMN_METADATA
endif
ifeq (1,$(opt.debug))
@@ -316,7 +323,7 @@ test-one: $(test.deps)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
test-sqllog: $(test.deps)
@echo "Testing with -sqllog..."
- $(bin.java) $(test.flags.jvm) -sqllog
+ $(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
test-mt: $(test.deps)
@echo "Testing in multi-threaded mode:";
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
diff --git a/ext/jni/README.md b/ext/jni/README.md
index f2811fddb2..fc7b5f7611 100644
--- a/ext/jni/README.md
+++ b/ext/jni/README.md
@@ -16,9 +16,8 @@ Technical support is available in the forum:
> **FOREWARNING:** this subproject is very much in development and
subject to any number of changes. Please do not rely on any
information about its API until this disclaimer is removed. The JNI
- bindings released with version 3.43 are a "tech preview" and 3.44
- will be "final," at which point strong backward compatibility
- guarantees will apply.
+ bindings released with version 3.43 are a "tech preview." Once
+ finalized, strong backward compatibility guarantees will apply.
Project goals/requirements:
@@ -43,11 +42,13 @@ Non-goals:
- Creation of high-level OO wrapper APIs. Clients are free to create
them off of the C-style API.
+- Virtual tables are unlikely to be supported due to the amount of
+ glue code needed to fit them into Java.
+
- Support for mixed-mode operation, where client code accesses SQLite
both via the Java-side API and the C API via their own native
- code. In such cases, proxy functionalities (primarily callback
- handler wrappers of all sorts) may fail because the C-side use of
- the SQLite APIs will bypass those proxies.
+ code. Such cases would be a minefield of potential mis-interactions
+ between this project's JNI bindings and mixed-mode client code.
Hello World
@@ -123,15 +124,13 @@ sensible default argument values. In all such cases they are thin
proxies around the corresponding C APIs and do not introduce new
semantics.
-In some very few cases, Java-specific capabilities have been added in
+In a few cases, Java-specific capabilities have been added in
new APIs, all of which have "_java" somewhere in their names.
Examples include:
- `sqlite3_result_java_object()`
- `sqlite3_column_java_object()`
-- `sqlite3_column_java_casted()`
- `sqlite3_value_java_object()`
-- `sqlite3_value_java_casted()`
which, as one might surmise, collectively enable the passing of
arbitrary Java objects from user-defined SQL functions through to the
@@ -150,6 +149,9 @@ pending statements have been closed. Be aware that Java garbage
collection _cannot_ close a database or finalize a prepared statement.
Those things require explicit API calls.
+Classes for which it is sensible support Java's `AutoCloseable`
+interface so can be used with try-with-resources constructs.
+
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
------------------------------------------------------------------------
@@ -159,14 +161,15 @@ retain C-like semantics. For example, they are not permitted to throw
or propagate exceptions and must return error information (if any) via
result codes or `null`. The only cases where the C-style APIs may
throw is through client-side misuse, e.g. passing in a null where it
-shouldn't be used. The APIs clearly mark function parameters which
-should not be null, but does not actively defend itself against such
-misuse. Some C-style APIs explicitly accept `null` as a no-op for
-usability's sake, and some of the JNI APIs deliberately return an
-error code, instead of segfaulting, when passed a `null`.
+may cause a `NullPointerException`. The APIs clearly mark function
+parameters which should not be null, but does not generally actively
+defend itself against such misuse. Some C-style APIs explicitly accept
+`null` as a no-op for usability's sake, and some of the JNI APIs
+deliberately return an error code, instead of segfaulting, when passed
+a `null`.
Client-defined callbacks _must never throw exceptions_ unless _very
-explicitly documented_ as being throw-safe. Exceptions are generally
+explitly documented_ as being throw-safe. Exceptions are generally
reserved for higher-level bindings which are constructed to
specifically deal with them and ensure that they do not leak C-level
resources. In some cases, callback handlers are permitted to throw, in
@@ -292,14 +295,14 @@ int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
`SQLFunction` is not used directly, but is instead instantiated via
one of its three subclasses:
-- `SQLFunction.Scalar` implements simple scalar functions using but a
+- `ScalarFunction` implements simple scalar functions using but a
single callback.
-- `SQLFunction.Aggregate` implements aggregate functions using two
+- `AggregateFunction` implements aggregate functions using two
callbacks.
-- `SQLFunction.Window` implements window functions using four
+- `WindowFunction` implements window functions using four
callbacks.
-Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/Tester1.java) for
+Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for
`SQLFunction` for how it's used.
Reminder: see the disclaimer at the top of this document regarding the
diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c
index 245ce4f9e9..5deff19ef1 100644
--- a/ext/jni/src/c/sqlite3-jni.c
+++ b/ext/jni/src/c/sqlite3-jni.c
@@ -15,13 +15,14 @@
/*
** If you found this comment by searching the code for
-** CallStaticObjectMethod then you're the victim of an OpenJDK bug:
+** CallStaticObjectMethod because it appears in console output then
+** you're probably the victim of an OpenJDK bug:
**
** https://bugs.openjdk.org/browse/JDK-8130659
**
-** It's known to happen with OpenJDK v8 but not with v19.
-**
-** This code does not use JNI's CallStaticObjectMethod().
+** It's known to happen with OpenJDK v8 but not with v19. It was
+** triggered by this code long before it made any use of
+** CallStaticObjectMethod().
*/
/*
@@ -90,12 +91,6 @@
#endif
#endif
-/**********************************************************************/
-/* SQLITE_M... */
-#ifndef SQLITE_MAX_ALLOCATION_SIZE
-# define SQLITE_MAX_ALLOCATION_SIZE 0x1fffffff
-#endif
-
/**********************************************************************/
/* SQLITE_O... */
#ifndef SQLITE_OMIT_DEPRECATED
@@ -112,6 +107,12 @@
# undef SQLITE_OMIT_UTF16 1
#endif
+/**********************************************************************/
+/* SQLITE_S... */
+#ifndef SQLITE_STRICT_SUBTYPE
+# define SQLITE_STRICT_SUBTYPE 1
+#endif
+
/**********************************************************************/
/* SQLITE_T... */
#ifndef SQLITE_TEMP_STORE
@@ -191,6 +192,8 @@
**
** This use of intptr_t is the _only_ reason we require
** which, in turn, requires building with -std=c99 (or later).
+**
+** See also: the notes for LongPtrGet_T.
*/
#define S3JniCast_L2P(JLongAsPtr) (void*)((intptr_t)(JLongAsPtr))
#define S3JniCast_P2L(PTR) (jlong)((intptr_t)(PTR))
@@ -207,8 +210,8 @@
**
** https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#jni_interface_functions_and_pointers
*/
-#define JniArgsEnvObj JNIEnv * const env, jobject jSelf
-#define JniArgsEnvClass JNIEnv * const env, jclass jKlazz
+#define JniArgsEnvObj JNIEnv * env, jobject jSelf
+#define JniArgsEnvClass JNIEnv * env, jclass jKlazz
/*
** Helpers to account for -Xcheck:jni warnings about not having
** checked for exceptions.
@@ -657,6 +660,21 @@ struct S3JniGlobalType {
jmethodID ctorLong1 /* the Long(long) constructor */;
jmethodID ctorStringBA /* the String(byte[],Charset) constructor */;
jmethodID stringGetBytes /* the String.getBytes(Charset) method */;
+
+ /*
+ ByteBuffer may or may not be supported via JNI on any given
+ platform:
+
+ https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#nio_support
+
+ We only store a ref to byteBuffer.klazz if JNI support for
+ ByteBuffer is available (which we determine during static init).
+ */
+ struct {
+ jclass klazz /* global ref to java.nio.ByteBuffer */;
+ jmethodID midAlloc /* ByteBuffer.allocateDirect() */;
+ jmethodID midLimit /* ByteBuffer.limit() */;
+ } byteBuffer;
} g;
/*
** The list of Java-side auto-extensions
@@ -863,6 +881,58 @@ static jbyte * s3jni__jbyteArray_bytes2(JNIEnv * const env, jbyteArray jBA, jsiz
#define s3jni_jbyteArray_commit(jByteArray,jBytes) \
if( jBytes ) (*env)->ReleaseByteArrayElements(env, jByteArray, jBytes, JNI_COMMIT)
+/*
+** If jbb is-a java.nio.Buffer object and the JNI environment supports
+** it, *pBuf is set to the buffer's memory and *pN is set to its
+** limit() (as opposed to its capacity()). If jbb is NULL, not a
+** Buffer, or the JNI environment does not support that operation,
+** *pBuf is set to 0 and *pN is set to 0.
+**
+** Note that the length of the buffer can be larger than SQLITE_LIMIT
+** but this function does not know what byte range of the buffer is
+** required so cannot check for that violation. The caller is required
+** to ensure that any to-be-bind()ed range fits within SQLITE_LIMIT.
+**
+** Sidebar: it is unfortunate that we cannot get ByteBuffer.limit()
+** via a JNI method like we can for ByteBuffer.capacity(). We instead
+** have to call back into Java to get the limit(). Depending on how
+** the ByteBuffer is used, the limit and capacity might be the same,
+** but when reusing a buffer, the limit may well change whereas the
+** capacity is fixed. The problem with, e.g., read()ing blob data to a
+** ByteBuffer's memory based on its capacity is that Java-level code
+** is restricted to accessing the range specified in
+** ByteBuffer.limit(). If we were to honor only the capacity, we
+** could end up writing to, or reading from, parts of a ByteBuffer
+** which client code itself cannot access without explicitly modifying
+** the limit. The penalty we pay for this correctness is that we must
+** call into Java to get the limit() of every ByteBuffer we work with.
+**
+** An alternative to having to call into ByteBuffer.limit() from here
+** would be to add private native impls of all ByteBuffer-using
+** methods, each of which adds a jint parameter which _must_ be set to
+** theBuffer.limit() by public Java APIs which use those private impls
+** to do the real work.
+*/
+static void s3jni__get_nio_buffer(JNIEnv * const env, jobject jbb, void **pBuf, jint * pN ){
+ *pBuf = 0;
+ *pN = 0;
+ if( jbb ){
+ *pBuf = (*env)->GetDirectBufferAddress(env, jbb);
+ if( *pBuf ){
+ /*
+ ** Maintenance reminder: do not use
+ ** (*env)->GetDirectBufferCapacity(env,jbb), even though it
+ ** would be much faster, for reasons explained in this
+ ** function's comments.
+ */
+ *pN = (*env)->CallIntMethod(env, jbb, SJG.g.byteBuffer.midLimit);
+ S3JniExceptionIsFatal("Error calling ByteBuffer.limit() method.");
+ }
+ }
+}
+#define s3jni_get_nio_buffer(JOBJ,vpOut,jpOut) \
+ s3jni__get_nio_buffer(env,(JOBJ),(vpOut),(jpOut))
+
/*
** Returns the current JNIEnv object. Fails fatally if it cannot find
** the object.
@@ -1061,6 +1131,47 @@ static jstring s3jni_text16_to_jstring(JNIEnv * const env, const void * const p,
return rv;
}
+/*
+** Creates a new ByteBuffer instance with a capacity of n. assert()s
+** that SJG.g.byteBuffer.klazz is not 0 and n>0.
+*/
+static jobject s3jni__new_ByteBuffer(JNIEnv * const env, int n){
+ jobject rv = 0;
+ assert( SJG.g.byteBuffer.klazz );
+ assert( SJG.g.byteBuffer.midAlloc );
+ assert( n > 0 );
+ rv = (*env)->CallStaticObjectMethod(env, SJG.g.byteBuffer.klazz,
+ SJG.g.byteBuffer.midAlloc, (jint)n);
+ S3JniIfThrew {
+ S3JniExceptionReport;
+ S3JniExceptionClear;
+ }
+ s3jni_oom_check( rv );
+ return rv;
+}
+
+/*
+** If n>0 and sqlite3_jni_supports_nio() is true then this creates a
+** new ByteBuffer object and copies n bytes from p to it. Returns NULL
+** if n is 0, sqlite3_jni_supports_nio() is false, or on allocation
+** error (unless fatal alloc failures are enabled).
+*/
+static jobject s3jni__blob_to_ByteBuffer(JNIEnv * const env,
+ const void * p, int n){
+ jobject rv = NULL;
+ assert( n >= 0 );
+ if( 0==n || !SJG.g.byteBuffer.klazz ){
+ return NULL;
+ }
+ rv = s3jni__new_ByteBuffer(env, n);
+ if( rv ){
+ void * tgt = (*env)->GetDirectBufferAddress(env, rv);
+ memcpy(tgt, p, (size_t)n);
+ }
+ return rv;
+}
+
+
/*
** Requires jx to be a Throwable. Calls its toString() method and
** returns its value converted to a UTF-8 string. The caller owns the
@@ -1472,15 +1583,15 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph,
** argument is a Java sqlite3 object, as this operation only has void
** pointers to work with.
*/
-#define PtrGet_T(T,OBJ) (T*)NativePointerHolder_get(OBJ, S3JniNph(T))
-#define PtrGet_sqlite3(OBJ) PtrGet_T(sqlite3, OBJ)
-#define PtrGet_sqlite3_backup(OBJ) PtrGet_T(sqlite3_backup, OBJ)
-#define PtrGet_sqlite3_blob(OBJ) PtrGet_T(sqlite3_blob, OBJ)
-#define PtrGet_sqlite3_context(OBJ) PtrGet_T(sqlite3_context, OBJ)
-#define PtrGet_sqlite3_stmt(OBJ) PtrGet_T(sqlite3_stmt, OBJ)
-#define PtrGet_sqlite3_value(OBJ) PtrGet_T(sqlite3_value, OBJ)
+#define PtrGet_T(T,JOBJ) (T*)NativePointerHolder_get((JOBJ), S3JniNph(T))
+#define PtrGet_sqlite3(JOBJ) PtrGet_T(sqlite3, (JOBJ))
+#define PtrGet_sqlite3_backup(JOBJ) PtrGet_T(sqlite3_backup, (JOBJ))
+#define PtrGet_sqlite3_blob(JOBJ) PtrGet_T(sqlite3_blob, (JOBJ))
+#define PtrGet_sqlite3_context(JOBJ) PtrGet_T(sqlite3_context, (JOBJ))
+#define PtrGet_sqlite3_stmt(JOBJ) PtrGet_T(sqlite3_stmt, (JOBJ))
+#define PtrGet_sqlite3_value(JOBJ) PtrGet_T(sqlite3_value, (JOBJ))
/*
-** S3JniLongPtr_T(X,Y) expects X to be an unqualified sqlite3 struct
+** LongPtrGet_T(X,Y) expects X to be an unqualified sqlite3 struct
** type name and Y to be a native pointer to such an object in the
** form of a jlong value. The jlong is simply cast to (X*). This
** approach is, as of 2023-09-27, supplanting the former approach. We
@@ -1488,13 +1599,22 @@ static void * NativePointerHolder__get(JNIEnv * env, jobject jNph,
** the C side, because it's reportedly significantly faster. The
** intptr_t part here is necessary for compatibility with (at least)
** ARM32.
+**
+** 2023-11-09: testing has not revealed any measurable performance
+** difference between the approach of passing type T to C compared to
+** passing pointer-to-T to C, and adding support for the latter
+** everywhere requires sigificantly more code. As of this writing, the
+** older/simpler approach is being applied except for (A) where the
+** newer approach has already been applied and (B) hot-spot APIs where
+** a difference of microseconds (i.e. below our testing measurement
+** threshold) might add up.
*/
-#define S3JniLongPtr_T(T,JLongAsPtr) (T*)((intptr_t)(JLongAsPtr))
-#define S3JniLongPtr_sqlite3(JLongAsPtr) S3JniLongPtr_T(sqlite3,JLongAsPtr)
-#define S3JniLongPtr_sqlite3_backup(JLongAsPtr) S3JniLongPtr_T(sqlite3_backup,JLongAsPtr)
-#define S3JniLongPtr_sqlite3_blob(JLongAsPtr) S3JniLongPtr_T(sqlite3_blob,JLongAsPtr)
-#define S3JniLongPtr_sqlite3_stmt(JLongAsPtr) S3JniLongPtr_T(sqlite3_stmt,JLongAsPtr)
-#define S3JniLongPtr_sqlite3_value(JLongAsPtr) S3JniLongPtr_T(sqlite3_value,JLongAsPtr)
+#define LongPtrGet_T(T,JLongAsPtr) (T*)((intptr_t)((JLongAsPtr)))
+#define LongPtrGet_sqlite3(JLongAsPtr) LongPtrGet_T(sqlite3,(JLongAsPtr))
+#define LongPtrGet_sqlite3_backup(JLongAsPtr) LongPtrGet_T(sqlite3_backup,(JLongAsPtr))
+#define LongPtrGet_sqlite3_blob(JLongAsPtr) LongPtrGet_T(sqlite3_blob,(JLongAsPtr))
+#define LongPtrGet_sqlite3_stmt(JLongAsPtr) LongPtrGet_T(sqlite3_stmt,(JLongAsPtr))
+#define LongPtrGet_sqlite3_value(JLongAsPtr) LongPtrGet_T(sqlite3_value,(JLongAsPtr))
/*
** Extracts the new S3JniDb instance from the free-list, or allocates
** one if needed, associates it with pDb, and returns. Returns NULL
@@ -1553,7 +1673,7 @@ static void S3JniDb_xDestroy(void *p){
#define S3JniDb_from_c(sqlite3Ptr) \
((sqlite3Ptr) ? S3JniDb_from_clientdata(sqlite3Ptr) : 0)
#define S3JniDb_from_jlong(sqlite3PtrAsLong) \
- S3JniDb_from_c(S3JniLongPtr_T(sqlite3,sqlite3PtrAsLong))
+ S3JniDb_from_c(LongPtrGet_T(sqlite3,sqlite3PtrAsLong))
/*
** Unref any Java-side state in (S3JniAutoExtension*) AX and zero out
@@ -1670,8 +1790,9 @@ static int encodingTypeIsValid(int eTextRep){
}
}
-/* For use with sqlite3_result/value_pointer() */
-static const char * const ResultJavaValuePtrStr = "org.sqlite.jni.capi.ResultJavaVal";
+/* For use with sqlite3_result_pointer(), sqlite3_value_pointer(),
+ sqlite3_bind_java_object(), and sqlite3_column_java_object(). */
+static const char * const s3jni__value_jref_key = "org.sqlite.jni.capi.ResultJavaVal";
/*
** If v is not NULL, it must be a jobject global reference. Its
@@ -1880,13 +2001,16 @@ static int udf_args(JNIEnv *env,
/*
** Requires that jCx and jArgv are sqlite3_context
-** resp. array-of-sqlite3_value values initialized by udf_args(). This
+** resp. array-of-sqlite3_value values initialized by udf_args(). The
+** latter will be 0-and-NULL for UDF types with no arguments. This
** function zeroes out the nativePointer member of jCx and each entry
** in jArgv. This is a safety-net precaution to avoid undefined
-** behavior if a Java-side UDF holds a reference to one of its
-** arguments. This MUST be called from any function which successfully
-** calls udf_args(), after calling the corresponding UDF and checking
-** its exception status. It MUST NOT be called in any other case.
+** behavior if a Java-side UDF holds a reference to its context or one
+** of its arguments. This MUST be called from any function which
+** successfully calls udf_args(), after calling the corresponding UDF
+** and checking its exception status, or which Java-wraps a
+** sqlite3_context for use with a UDF(ish) call. It MUST NOT be called
+** in any other case.
*/
static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
int i = 0;
@@ -1894,8 +2018,29 @@ static void udf_unargs(JNIEnv *env, jobject jCx, int argc, jobjectArray jArgv){
NativePointerHolder_set(S3JniNph(sqlite3_context), jCx, 0);
for( ; i < argc; ++i ){
jobject jsv = (*env)->GetObjectArrayElement(env, jArgv, i);
- assert(jsv);
- NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
+ /*
+ ** There is a potential Java-triggerable case of Undefined
+ ** Behavior here, but it would require intentional misuse of the
+ ** API:
+ **
+ ** If a Java UDF grabs an sqlite3_value from its argv and then
+ ** assigns that element to null, it becomes unreachable to us so
+ ** we cannot clear out its pointer. That Java-side object's
+ ** getNativePointer() will then refer to a stale value, so passing
+ ** it into (e.g.) sqlite3_value_SOMETHING() would invoke UB.
+ **
+ ** High-level wrappers can avoid that possibility if they do not
+ ** expose sqlite3_value directly to clients (as is the case in
+ ** org.sqlite.jni.wrapper1.SqlFunction).
+ **
+ ** One potential (but expensive) workaround for this would be to
+ ** privately store a duplicate argv array in each sqlite3_context
+ ** wrapper object, and clear the native pointers from that copy.
+ */
+ assert(jsv && "Someone illegally modified a UDF argument array.");
+ if( jsv ){
+ NativePointerHolder_set(S3JniNph(sqlite3_value), jsv, 0);
+ }
}
}
@@ -1984,6 +2129,7 @@ static int udf_xFV(sqlite3_context* cx, S3JniUdf * s,
rc = udf_report_exception(env, isFinal, cx, s->zFuncName,
zFuncType);
}
+ udf_unargs(env, jcx, 0, 0);
S3JniUnrefLocal(jcx);
}else{
if( isFinal ) sqlite3_result_error_nomem(cx);
@@ -2057,12 +2203,12 @@ static void udf_xInverse(sqlite3_context* cx, int argc,
/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*)). */
#define WRAP_INT_STMT(JniNameSuffix,CName) \
JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt){ \
- return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt)); \
+ return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt)); \
}
/** Create a trivial JNI wrapper for (int CName(sqlite3_stmt*,int)). */
#define WRAP_INT_STMT_INT(JniNameSuffix,CName) \
JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint n){ \
- return (jint)CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)n); \
+ return (jint)CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)n); \
}
/** Create a trivial JNI wrapper for (boolean CName(sqlite3_stmt*)). */
#define WRAP_BOOL_STMT(JniNameSuffix,CName) \
@@ -2073,41 +2219,41 @@ static void udf_xInverse(sqlite3_context* cx, int argc,
#define WRAP_STR_STMT_INT(JniNameSuffix,CName) \
JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpStmt, jint ndx){ \
return s3jni_utf8_to_jstring( \
- CName(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx), \
+ CName(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx), \
-1); \
}
/** Create a trivial JNI wrapper for (boolean CName(sqlite3*)). */
#define WRAP_BOOL_DB(JniNameSuffix,CName) \
JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \
- return CName(S3JniLongPtr_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \
+ return CName(LongPtrGet_sqlite3(jpDb)) ? JNI_TRUE : JNI_FALSE; \
}
/** Create a trivial JNI wrapper for (int CName(sqlite3*)). */
#define WRAP_INT_DB(JniNameSuffix,CName) \
JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \
- return (jint)CName(S3JniLongPtr_sqlite3(jpDb)); \
+ return (jint)CName(LongPtrGet_sqlite3(jpDb)); \
}
/** Create a trivial JNI wrapper for (int64 CName(sqlite3*)). */
#define WRAP_INT64_DB(JniNameSuffix,CName) \
JniDecl(jlong,JniNameSuffix)(JniArgsEnvClass, jlong jpDb){ \
- return (jlong)CName(S3JniLongPtr_sqlite3(jpDb)); \
+ return (jlong)CName(LongPtrGet_sqlite3(jpDb)); \
}
/** Create a trivial JNI wrapper for (jstring CName(sqlite3*,int)). */
#define WRAP_STR_DB_INT(JniNameSuffix,CName) \
JniDecl(jstring,JniNameSuffix)(JniArgsEnvClass, jlong jpDb, jint ndx){ \
return s3jni_utf8_to_jstring( \
- CName(S3JniLongPtr_sqlite3(jpDb), (int)ndx), \
+ CName(LongPtrGet_sqlite3(jpDb), (int)ndx), \
-1); \
}
/** Create a trivial JNI wrapper for (int CName(sqlite3_value*)). */
#define WRAP_INT_SVALUE(JniNameSuffix,CName,DfltOnNull) \
JniDecl(jint,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \
return (jint)(sv ? CName(sv): DfltOnNull); \
}
/** Create a trivial JNI wrapper for (boolean CName(sqlite3_value*)). */
#define WRAP_BOOL_SVALUE(JniNameSuffix,CName,DfltOnNull) \
JniDecl(jboolean,JniNameSuffix)(JniArgsEnvClass, jlong jpSValue){ \
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSValue); \
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSValue); \
return (jint)(sv ? CName(sv) : DfltOnNull) \
? JNI_TRUE : JNI_FALSE; \
}
@@ -2120,9 +2266,11 @@ WRAP_INT_STMT_INT(1column_1bytes16, sqlite3_column_bytes16)
WRAP_INT_STMT(1column_1count, sqlite3_column_count)
WRAP_STR_STMT_INT(1column_1decltype, sqlite3_column_decltype)
WRAP_STR_STMT_INT(1column_1name, sqlite3_column_name)
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
WRAP_STR_STMT_INT(1column_1database_1name, sqlite3_column_database_name)
WRAP_STR_STMT_INT(1column_1origin_1name, sqlite3_column_origin_name)
WRAP_STR_STMT_INT(1column_1table_1name, sqlite3_column_table_name)
+#endif
WRAP_INT_STMT_INT(1column_1type, sqlite3_column_type)
WRAP_INT_STMT(1data_1count, sqlite3_data_count)
WRAP_STR_DB_INT(1db_1name, sqlite3_db_name)
@@ -2181,7 +2329,9 @@ S3JniApi(sqlite3_aggregate_context(),jlong,1aggregate_1context)(
return S3JniCast_P2L(p);
}
-/* Central auto-extension handler. */
+/*
+** Central auto-extension runner for auto-extensions created in Java.
+*/
static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
const struct sqlite3_api_routines *ignored){
int rc = 0;
@@ -2318,7 +2468,7 @@ S3JniApi(sqlite3_backup_finish(),jint,1backup_1finish)(
){
int rc = 0;
if( jpBack!=0 ){
- rc = sqlite3_backup_finish( S3JniLongPtr_sqlite3_backup(jpBack) );
+ rc = sqlite3_backup_finish( LongPtrGet_sqlite3_backup(jpBack) );
}
return rc;
}
@@ -2327,8 +2477,8 @@ S3JniApi(sqlite3_backup_init(),jobject,1backup_1init)(
JniArgsEnvClass, jlong jpDbDest, jstring jTDest,
jlong jpDbSrc, jstring jTSrc
){
- sqlite3 * const pDest = S3JniLongPtr_sqlite3(jpDbDest);
- sqlite3 * const pSrc = S3JniLongPtr_sqlite3(jpDbSrc);
+ sqlite3 * const pDest = LongPtrGet_sqlite3(jpDbDest);
+ sqlite3 * const pSrc = LongPtrGet_sqlite3(jpDbSrc);
char * const zDest = s3jni_jstring_to_utf8(jTDest, 0);
char * const zSrc = s3jni_jstring_to_utf8(jTSrc, 0);
jobject rv = 0;
@@ -2351,19 +2501,19 @@ S3JniApi(sqlite3_backup_init(),jobject,1backup_1init)(
S3JniApi(sqlite3_backup_pagecount(),jint,1backup_1pagecount)(
JniArgsEnvClass, jlong jpBack
){
- return sqlite3_backup_pagecount(S3JniLongPtr_sqlite3_backup(jpBack));
+ return sqlite3_backup_pagecount(LongPtrGet_sqlite3_backup(jpBack));
}
S3JniApi(sqlite3_backup_remaining(),jint,1backup_1remaining)(
JniArgsEnvClass, jlong jpBack
){
- return sqlite3_backup_remaining(S3JniLongPtr_sqlite3_backup(jpBack));
+ return sqlite3_backup_remaining(LongPtrGet_sqlite3_backup(jpBack));
}
S3JniApi(sqlite3_backup_step(),jint,1backup_1step)(
JniArgsEnvClass, jlong jpBack, jint nPage
){
- return sqlite3_backup_step(S3JniLongPtr_sqlite3_backup(jpBack), (int)nPage);
+ return sqlite3_backup_step(LongPtrGet_sqlite3_backup(jpBack), (int)nPage);
}
S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)(
@@ -2376,34 +2526,140 @@ S3JniApi(sqlite3_bind_blob(),jint,1bind_1blob)(
if( nMax>nBA ){
nMax = nBA;
}
- rc = sqlite3_bind_blob(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
+ rc = sqlite3_bind_blob(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
pBuf, (int)nMax, SQLITE_TRANSIENT);
s3jni_jbyteArray_release(baData, pBuf);
}else{
rc = baData
? SQLITE_NOMEM
- : sqlite3_bind_null( S3JniLongPtr_sqlite3_stmt(jpStmt), ndx );
+ : sqlite3_bind_null( LongPtrGet_sqlite3_stmt(jpStmt), ndx );
}
return (jint)rc;
}
+/**
+ Helper for use with s3jni_setup_nio_args().
+*/
+struct S3JniNioArgs {
+ jobject jBuf; /* input - ByteBuffer */
+ jint iOffset; /* input - byte offset */
+ jint iHowMany; /* input - byte count to bind/read/write */
+ jint nBuf; /* output - jBuf's buffer size */
+ void * p; /* output - jBuf's buffer memory */
+ void * pStart; /* output - offset of p to bind/read/write */
+ int nOut; /* output - number of bytes from pStart to bind/read/write */
+};
+typedef struct S3JniNioArgs S3JniNioArgs;
+static const S3JniNioArgs S3JniNioArgs_empty = {
+ 0,0,0,0,0,0,0
+};
+
+/*
+** Internal helper for sqlite3_bind_nio_buffer(),
+** sqlite3_result_nio_buffer(), and similar methods which take a
+** ByteBuffer object as either input or output. Populates pArgs and
+** returns 0 on success, non-0 if the operation should fail. The
+** caller is required to check for SJG.g.byteBuffer.klazz!=0 before calling
+** this and reporting it in a way appropriate for that routine. This
+** function may assert() that SJG.g.byteBuffer.klazz is not 0.
+**
+** The (jBuffer, iOffset, iHowMany) arguments are the (ByteBuffer, offset,
+** length) arguments to the bind/result method.
+**
+** If iHowMany is negative then it's treated as "until the end" and
+** the calculated slice is trimmed to fit if needed. If iHowMany is
+** positive and extends past the end of jBuffer then SQLITE_ERROR is
+** returned.
+**
+** Returns 0 if everything looks to be in order, else some SQLITE_...
+** result code
+*/
+static int s3jni_setup_nio_args(
+ JNIEnv *env, S3JniNioArgs * pArgs,
+ jobject jBuffer, jint iOffset, jint iHowMany
+){
+ jlong iEnd = 0;
+ const int bAllowTruncate = iHowMany<0;
+ *pArgs = S3JniNioArgs_empty;
+ pArgs->jBuf = jBuffer;
+ pArgs->iOffset = iOffset;
+ pArgs->iHowMany = iHowMany;
+ assert( SJG.g.byteBuffer.klazz );
+ if( pArgs->iOffset<0 ){
+ return SQLITE_ERROR
+ /* SQLITE_MISUSE or SQLITE_RANGE would fit better but we use
+ SQLITE_ERROR for consistency with the code documented for a
+ negative target blob offset in sqlite3_blob_read/write(). */;
+ }
+ s3jni_get_nio_buffer(pArgs->jBuf, &pArgs->p, &pArgs->nBuf);
+ if( !pArgs->p ){
+ return SQLITE_MISUSE;
+ }else if( pArgs->iOffset>=pArgs->nBuf ){
+ pArgs->pStart = 0;
+ pArgs->nOut = 0;
+ return 0;
+ }
+ assert( pArgs->nBuf > 0 );
+ assert( pArgs->iOffset < pArgs->nBuf );
+ iEnd = pArgs->iHowMany<0
+ ? pArgs->nBuf - pArgs->iOffset
+ : pArgs->iOffset + pArgs->iHowMany;
+ if( iEnd>(jlong)pArgs->nBuf ){
+ if( bAllowTruncate ){
+ iEnd = pArgs->nBuf - pArgs->iOffset;
+ }else{
+ return SQLITE_ERROR
+ /* again: for consistency with blob_read/write(), though
+ SQLITE_MISUSE or SQLITE_RANGE would be a better fit. */;
+ }
+ }
+ if( iEnd - pArgs->iOffset > (jlong)SQLITE_MAX_LENGTH ){
+ return SQLITE_TOOBIG;
+ }
+ assert( pArgs->iOffset >= 0 );
+ assert( iEnd > pArgs->iOffset );
+ pArgs->pStart = pArgs->p + pArgs->iOffset;
+ pArgs->nOut = (int)(iEnd - pArgs->iOffset);
+ assert( pArgs->nOut > 0 );
+ assert( (pArgs->pStart + pArgs->nOut) <= (pArgs->p + pArgs->nBuf) );
+ return 0;
+}
+
+S3JniApi(sqlite3_bind_nio_buffer(),jint,1bind_1nio_1buffer)(
+ JniArgsEnvClass, jobject jpStmt, jint ndx, jobject jBuffer,
+ jint iOffset, jint iN
+){
+ sqlite3_stmt * pStmt = PtrGet_sqlite3_stmt(jpStmt);
+ S3JniNioArgs args;
+ int rc;
+ if( !pStmt || !SJG.g.byteBuffer.klazz ) return SQLITE_MISUSE;
+ rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
+ if(rc){
+ return rc;
+ }else if( !args.pStart || !args.nOut ){
+ return sqlite3_bind_null(pStmt, ndx);
+ }
+ return sqlite3_bind_blob( pStmt, (int)ndx, args.pStart,
+ args.nOut, SQLITE_TRANSIENT );
+}
+
S3JniApi(sqlite3_bind_double(),jint,1bind_1double)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jdouble val
){
- return (jint)sqlite3_bind_double(S3JniLongPtr_sqlite3_stmt(jpStmt),
+ return (jint)sqlite3_bind_double(LongPtrGet_sqlite3_stmt(jpStmt),
(int)ndx, (double)val);
}
S3JniApi(sqlite3_bind_int(),jint,1bind_1int)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jint val
){
- return (jint)sqlite3_bind_int(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (int)val);
+ return (jint)sqlite3_bind_int(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (int)val);
}
S3JniApi(sqlite3_bind_int64(),jint,1bind_1int64)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jlong val
){
- return (jint)sqlite3_bind_int64(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val);
+ return (jint)sqlite3_bind_int64(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx, (sqlite3_int64)val);
}
/*
@@ -2412,13 +2668,13 @@ S3JniApi(sqlite3_bind_int64(),jint,1bind_1int64)(
S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jobject val
){
- sqlite3_stmt * const pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt);
+ sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
int rc = SQLITE_MISUSE;
if(pStmt){
jobject const rv = S3JniRefGlobal(val);
if( rv ){
- rc = sqlite3_bind_pointer(pStmt, ndx, rv, ResultJavaValuePtrStr,
+ rc = sqlite3_bind_pointer(pStmt, ndx, rv, s3jni__value_jref_key,
S3Jni_jobject_finalizer);
}else if(val){
rc = SQLITE_NOMEM;
@@ -2432,13 +2688,13 @@ S3JniApi(sqlite3_bind_java_object(),jint,1bind_1java_1object)(
S3JniApi(sqlite3_bind_null(),jint,1bind_1null)(
JniArgsEnvClass, jlong jpStmt, jint ndx
){
- return (jint)sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx);
+ return (jint)sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx);
}
S3JniApi(sqlite3_bind_parameter_count(),jint,1bind_1parameter_1count)(
JniArgsEnvClass, jlong jpStmt
){
- return (jint)sqlite3_bind_parameter_count(S3JniLongPtr_sqlite3_stmt(jpStmt));
+ return (jint)sqlite3_bind_parameter_count(LongPtrGet_sqlite3_stmt(jpStmt));
}
S3JniApi(sqlite3_bind_parameter_index(),jint,1bind_1parameter_1index)(
@@ -2447,7 +2703,7 @@ S3JniApi(sqlite3_bind_parameter_index(),jint,1bind_1parameter_1index)(
int rc = 0;
jbyte * const pBuf = s3jni_jbyteArray_bytes(jName);
if( pBuf ){
- rc = sqlite3_bind_parameter_index(S3JniLongPtr_sqlite3_stmt(jpStmt),
+ rc = sqlite3_bind_parameter_index(LongPtrGet_sqlite3_stmt(jpStmt),
(const char *)pBuf);
s3jni_jbyteArray_release(jName, pBuf);
}
@@ -2458,7 +2714,7 @@ S3JniApi(sqlite3_bind_parameter_name(),jstring,1bind_1parameter_1name)(
JniArgsEnvClass, jlong jpStmt, jint ndx
){
const char *z =
- sqlite3_bind_parameter_name(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx);
+ sqlite3_bind_parameter_name(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx);
return z ? s3jni_utf8_to_jstring(z, -1) : 0;
}
@@ -2480,14 +2736,14 @@ static int s3jni__bind_text(int is16, JNIEnv *env, jlong jpStmt, jint ndx,
such cases, we do not expose the byte-limit arguments in the
public API. */
rc = is16
- ? sqlite3_bind_text16(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
+ ? sqlite3_bind_text16(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
pBuf, (int)nMax, SQLITE_TRANSIENT)
- : sqlite3_bind_text(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx,
+ : sqlite3_bind_text(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx,
(const char *)pBuf,
(int)nMax, SQLITE_TRANSIENT);
}else{
rc = baData
- ? sqlite3_bind_null(S3JniLongPtr_sqlite3_stmt(jpStmt), (int)ndx)
+ ? sqlite3_bind_null(LongPtrGet_sqlite3_stmt(jpStmt), (int)ndx)
: SQLITE_NOMEM;
}
s3jni_jbyteArray_release(baData, pBuf);
@@ -2511,9 +2767,9 @@ S3JniApi(sqlite3_bind_value(),jint,1bind_1value)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jlong jpValue
){
int rc = 0;
- sqlite3_stmt * pStmt = S3JniLongPtr_sqlite3_stmt(jpStmt);
+ sqlite3_stmt * pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
- sqlite3_value *v = S3JniLongPtr_sqlite3_value(jpValue);
+ sqlite3_value *v = LongPtrGet_sqlite3_value(jpValue);
if( v ){
rc = sqlite3_bind_value(pStmt, (int)ndx, v);
}else{
@@ -2528,27 +2784,27 @@ S3JniApi(sqlite3_bind_value(),jint,1bind_1value)(
S3JniApi(sqlite3_bind_zeroblob(),jint,1bind_1zeroblob)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jint n
){
- return (jint)sqlite3_bind_zeroblob(S3JniLongPtr_sqlite3_stmt(jpStmt),
+ return (jint)sqlite3_bind_zeroblob(LongPtrGet_sqlite3_stmt(jpStmt),
(int)ndx, (int)n);
}
S3JniApi(sqlite3_bind_zeroblob64(),jint,1bind_1zeroblob64)(
JniArgsEnvClass, jlong jpStmt, jint ndx, jlong n
){
- return (jint)sqlite3_bind_zeroblob64(S3JniLongPtr_sqlite3_stmt(jpStmt),
+ return (jint)sqlite3_bind_zeroblob64(LongPtrGet_sqlite3_stmt(jpStmt),
(int)ndx, (sqlite3_uint64)n);
}
S3JniApi(sqlite3_blob_bytes(),jint,1blob_1bytes)(
JniArgsEnvClass, jlong jpBlob
){
- return sqlite3_blob_bytes(S3JniLongPtr_sqlite3_blob(jpBlob));
+ return sqlite3_blob_bytes(LongPtrGet_sqlite3_blob(jpBlob));
}
S3JniApi(sqlite3_blob_close(),jint,1blob_1close)(
JniArgsEnvClass, jlong jpBlob
){
- sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob);
+ sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
return b ? (jint)sqlite3_blob_close(b) : SQLITE_MISUSE;
}
@@ -2556,7 +2812,7 @@ S3JniApi(sqlite3_blob_open(),jint,1blob_1open)(
JniArgsEnvClass, jlong jpDb, jstring jDbName, jstring jTbl, jstring jCol,
jlong jRowId, jint flags, jobject jOut
){
- sqlite3 * const db = S3JniLongPtr_sqlite3(jpDb);
+ sqlite3 * const db = LongPtrGet_sqlite3(jpDb);
sqlite3_blob * pBlob = 0;
char * zDbName = 0, * zTableName = 0, * zColumnName = 0;
int rc;
@@ -2590,7 +2846,7 @@ S3JniApi(sqlite3_blob_read(),jint,1blob_1read)(
int rc = jTgt ? (pBa ? SQLITE_MISUSE : SQLITE_NOMEM) : SQLITE_MISUSE;
if( pBa ){
jsize const nTgt = (*env)->GetArrayLength(env, jTgt);
- rc = sqlite3_blob_read(S3JniLongPtr_sqlite3_blob(jpBlob), pBa,
+ rc = sqlite3_blob_read(LongPtrGet_sqlite3_blob(jpBlob), pBa,
(int)nTgt, (int)iOffset);
if( 0==rc ){
s3jni_jbyteArray_commit(jTgt, pBa);
@@ -2601,17 +2857,41 @@ S3JniApi(sqlite3_blob_read(),jint,1blob_1read)(
return rc;
}
+S3JniApi(sqlite3_blob_read_nio_buffer(),jint,1blob_1read_1nio_1buffer)(
+ JniArgsEnvClass, jlong jpBlob, jint iSrcOff, jobject jBB, jint iTgtOff, jint iHowMany
+){
+ sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
+ S3JniNioArgs args;
+ int rc;
+ if( !b || !SJG.g.byteBuffer.klazz || iHowMany<0 ){
+ return SQLITE_MISUSE;
+ }else if( iTgtOff<0 || iSrcOff<0 ){
+ return SQLITE_ERROR
+ /* for consistency with underlying sqlite3_blob_read() */;
+ }else if( 0==iHowMany ){
+ return 0;
+ }
+ rc = s3jni_setup_nio_args(env, &args, jBB, iTgtOff, iHowMany);
+ if(rc){
+ return rc;
+ }else if( !args.pStart || !args.nOut ){
+ return 0;
+ }
+ assert( args.iHowMany>0 );
+ return sqlite3_blob_read( b, args.pStart, (int)args.nOut, (int)iSrcOff );
+}
+
S3JniApi(sqlite3_blob_reopen(),jint,1blob_1reopen)(
JniArgsEnvClass, jlong jpBlob, jlong iNewRowId
){
- return (jint)sqlite3_blob_reopen(S3JniLongPtr_sqlite3_blob(jpBlob),
+ return (jint)sqlite3_blob_reopen(LongPtrGet_sqlite3_blob(jpBlob),
(sqlite3_int64)iNewRowId);
}
S3JniApi(sqlite3_blob_write(),jint,1blob_1write)(
JniArgsEnvClass, jlong jpBlob, jbyteArray jBa, jint iOffset
){
- sqlite3_blob * const b = S3JniLongPtr_sqlite3_blob(jpBlob);
+ sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
jbyte * const pBuf = b ? s3jni_jbyteArray_bytes(jBa) : 0;
const jsize nBA = pBuf ? (*env)->GetArrayLength(env, jBa) : 0;
int rc = SQLITE_MISUSE;
@@ -2622,6 +2902,29 @@ S3JniApi(sqlite3_blob_write(),jint,1blob_1write)(
return (jint)rc;
}
+S3JniApi(sqlite3_blob_write_nio_buffer(),jint,1blob_1write_1nio_1buffer)(
+ JniArgsEnvClass, jlong jpBlob, jint iTgtOff, jobject jBB, jint iSrcOff, jint iHowMany
+){
+ sqlite3_blob * const b = LongPtrGet_sqlite3_blob(jpBlob);
+ S3JniNioArgs args;
+ int rc;
+ if( !b || !SJG.g.byteBuffer.klazz ){
+ return SQLITE_MISUSE;
+ }else if( iTgtOff<0 || iSrcOff<0 ){
+ return SQLITE_ERROR
+ /* for consistency with underlying sqlite3_blob_write() */;
+ }else if( 0==iHowMany ){
+ return 0;
+ }
+ rc = s3jni_setup_nio_args(env, &args, jBB, iSrcOff, iHowMany);
+ if(rc){
+ return rc;
+ }else if( !args.pStart || !args.nOut ){
+ return 0;
+ }
+ return sqlite3_blob_write( b, args.pStart, (int)args.nOut, (int)iTgtOff );
+}
+
/* Central C-to-Java busy handler proxy. */
static int s3jni_busy_handler(void* pState, int n){
S3JniDb * const ps = (S3JniDb *)pState;
@@ -2820,7 +3123,7 @@ S3JniApi(sqlite3_collation_needed(),jint,1collation_1needed)(
}else{
jclass const klazz = (*env)->GetObjectClass(env, jHook);
jmethodID const xCallback = (*env)->GetMethodID(
- env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I"
+ env, klazz, "call", "(Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)V"
);
S3JniUnrefLocal(klazz);
S3JniIfThrew {
@@ -2870,6 +3173,41 @@ S3JniApi(sqlite3_column_int64(),jlong,1column_1int64)(
return (jlong)sqlite3_column_int64(PtrGet_sqlite3_stmt(jpStmt), (int)ndx);
}
+S3JniApi(sqlite3_column_java_object(),jobject,1column_1java_1object)(
+ JniArgsEnvClass, jlong jpStmt, jint ndx
+){
+ sqlite3_stmt * const stmt = LongPtrGet_sqlite3_stmt(jpStmt);
+ jobject rv = 0;
+ if( stmt ){
+ sqlite3 * const db = sqlite3_db_handle(stmt);
+ sqlite3_value * sv;
+ sqlite3_mutex_enter(sqlite3_db_mutex(db));
+ sv = sqlite3_column_value(stmt, (int)ndx);
+ if( sv ){
+ rv = S3JniRefLocal(
+ sqlite3_value_pointer(sv, s3jni__value_jref_key)
+ );
+ }
+ sqlite3_mutex_leave(sqlite3_db_mutex(db));
+ }
+ return rv;
+}
+
+S3JniApi(sqlite3_column_nio_buffer(),jobject,1column_1nio_1buffer)(
+ JniArgsEnvClass, jobject jStmt, jint ndx
+){
+ sqlite3_stmt * const stmt = PtrGet_sqlite3_stmt(jStmt);
+ jobject rv = 0;
+ if( stmt ){
+ const void * const p = sqlite3_column_blob(stmt, (int)ndx);
+ if( p ){
+ const int n = sqlite3_column_bytes(stmt, (int)ndx);
+ rv = s3jni__blob_to_ByteBuffer(env, p, n);
+ }
+ }
+ return rv;
+}
+
S3JniApi(sqlite3_column_text(),jbyteArray,1column_1text)(
JniArgsEnvClass, jobject jpStmt, jint ndx
){
@@ -2925,7 +3263,10 @@ static int s3jni_commit_rollback_hook_impl(int isCommit, S3JniDb * const ps){
? (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback)
: (int)((*env)->CallVoidMethod(env, hook.jObj, hook.midCallback), 0);
S3JniIfThrew{
- rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR, "hook callback threw");
+ rc = s3jni_db_exception(ps->pDb, SQLITE_ERROR,
+ isCommit
+ ? "Commit hook callback threw"
+ : "Rollback hook callback threw");
}
S3JniHook_localundup(hook);
}
@@ -3028,7 +3369,7 @@ S3JniApi(sqlite3_compileoption_used(),jboolean,1compileoption_1used)(
return rc;
}
-S3JniApi(sqlite3_complete(),int,1complete)(
+S3JniApi(sqlite3_complete(),jint,1complete)(
JniArgsEnvClass, jbyteArray jSql
){
jbyte * const pBuf = s3jni_jbyteArray_bytes(jSql);
@@ -3044,8 +3385,9 @@ S3JniApi(sqlite3_complete(),int,1complete)(
return rc;
}
-S3JniApi(sqlite3_config() /*for a small subset of options.*/,
- jint,1config__I)(JniArgsEnvClass, jint n){
+S3JniApi(sqlite3_config() /*for a small subset of options.*/
+ sqlite3_config__enable()/* internal name to avoid name-mangling issues*/,
+ jint,1config_1_1enable)(JniArgsEnvClass, jint n){
switch( n ){
case SQLITE_CONFIG_SINGLETHREAD:
case SQLITE_CONFIG_MULTITHREAD:
@@ -3075,8 +3417,9 @@ static void s3jni_config_log(void *ignored, int errCode, const char *z){
}
}
-S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */,
- jint, 1config__Lorg_sqlite_jni_ConfigLogCallback_2
+S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_LOG */
+ sqlite3_config__config_log() /* internal name */,
+ jint, 1config_1_1CONFIG_1LOG
)(JniArgsEnvClass, jobject jLog){
S3JniHook * const pHook = &SJG.hook.configlog;
int rc = 0;
@@ -3150,9 +3493,10 @@ void sqlite3_init_sqllog(void){
}
#endif
-S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */,
- jint, 1config__Lorg_sqlite_jni_ConfigSqllogCallback_2)(
- JniArgsEnvClass, jobject jLog){
+S3JniApi(sqlite3_config() /* for SQLITE_CONFIG_SQLLOG */
+ sqlite3_config__SQLLOG() /*internal name*/,
+ jint, 1config_1_1SQLLOG
+)(JniArgsEnvClass, jobject jLog){
#ifndef SQLITE_ENABLE_SQLLOG
return SQLITE_MISUSE;
#else
@@ -3412,7 +3756,6 @@ S3JniApi(
}
break;
}
- case 0:
default:
rc = SQLITE_MISUSE;
}
@@ -3475,7 +3818,7 @@ S3JniApi(sqlite3_db_readonly(),jint,1db_1readonly)(
return (jint)rc;
}
-S3JniApi(sqlite3_db_release_memory(),int,1db_1release_1memory)(
+S3JniApi(sqlite3_db_release_memory(),jint,1db_1release_1memory)(
JniArgsEnvClass, jobject jDb
){
sqlite3 * const pDb = PtrGet_sqlite3(jDb);
@@ -3516,9 +3859,16 @@ S3JniApi(sqlite3_errmsg(),jstring,1errmsg)(
S3JniApi(sqlite3_errstr(),jstring,1errstr)(
JniArgsEnvClass, jint rcCode
){
- jstring const rv = (*env)->NewStringUTF(env, sqlite3_errstr((int)rcCode))
- /* We know these values to be plain ASCII, so pose no MUTF-8
- ** incompatibility */;
+ jstring rv;
+ const char * z = sqlite3_errstr((int)rcCode);
+ if( !z ){
+ /* This hypothetically cannot happen, but we'll behave like the
+ low-level library would in such a case... */
+ z = "unknown error";
+ }
+ rv = (*env)->NewStringUTF(env, z)
+ /* We know these values to be plain ASCII, so pose no MUTF-8
+ ** incompatibility */;
s3jni_oom_check( rv );
return rv;
}
@@ -3570,19 +3920,21 @@ S3JniApi(sqlite3_normalized_sql(),jstring,1normalized_1sql)(
#endif
}
-S3JniApi(sqlite3_extended_result_codes(),jboolean,1extended_1result_1codes)(
+S3JniApi(sqlite3_extended_result_codes(),jint,1extended_1result_1codes)(
JniArgsEnvClass, jobject jpDb, jboolean onoff
){
sqlite3 * const pDb = PtrGet_sqlite3(jpDb);
- int const rc = pDb ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0) : 0;
- return rc ? JNI_TRUE : JNI_FALSE;
+ int const rc = pDb
+ ? sqlite3_extended_result_codes(pDb, onoff ? 1 : 0)
+ : SQLITE_MISUSE;
+ return rc;
}
S3JniApi(sqlite3_finalize(),jint,1finalize)(
JniArgsEnvClass, jlong jpStmt
){
return jpStmt
- ? sqlite3_finalize(S3JniLongPtr_sqlite3_stmt(jpStmt))
+ ? sqlite3_finalize(LongPtrGet_sqlite3_stmt(jpStmt))
: 0;
}
@@ -3623,7 +3975,9 @@ S3JniApi(sqlite3_is_interrupted(),jboolean,1is_1interrupted)(
** any resources owned by that cache entry and making that slot
** available for re-use.
*/
-JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
+S3JniApi(sqlite3_java_uncache_thread(), jboolean, 1java_1uncache_1thread)(
+ JniArgsEnvClass
+){
int rc;
S3JniEnv_mutex_enter;
rc = S3JniEnv_uncache(env);
@@ -3631,6 +3985,29 @@ JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
return rc ? JNI_TRUE : JNI_FALSE;
}
+S3JniApi(sqlite3_jni_db_error(), jint, 1jni_1db_1error)(
+ JniArgsEnvClass, jobject jDb, jint jRc, jstring jStr
+){
+ S3JniDb * const ps = S3JniDb_from_java(jDb);
+ int rc = SQLITE_MISUSE;
+ if( ps ){
+ char *zStr;
+ zStr = jStr
+ ? s3jni_jstring_to_utf8( jStr, 0)
+ : NULL;
+ rc = s3jni_db_error( ps->pDb, (int)jRc, zStr );
+ sqlite3_free(zStr);
+ }
+ return rc;
+}
+
+S3JniApi(sqlite3_jni_supports_nio(), jboolean,1jni_1supports_1nio)(
+ JniArgsEnvClass
+){
+ return SJG.g.byteBuffer.klazz ? JNI_TRUE : JNI_FALSE;
+}
+
+
S3JniApi(sqlite3_keyword_check(),jboolean,1keyword_1check)(
JniArgsEnvClass, jstring jWord
){
@@ -3804,14 +4181,15 @@ S3JniApi(sqlite3_open_v2(),jint,1open_1v2)(
}
/* Proxy for the sqlite3_prepare[_v2/3]() family. */
-jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env, jclass self,
- jlong jpDb, jbyteArray baSql,
- jint nMax, jint prepFlags,
- jobject jOutStmt, jobject outTail){
+static jint sqlite3_jni_prepare_v123( int prepVersion, JNIEnv * const env,
+ jclass self,
+ jlong jpDb, jbyteArray baSql,
+ jint nMax, jint prepFlags,
+ jobject jOutStmt, jobject outTail){
sqlite3_stmt * pStmt = 0;
jobject jStmt = 0;
const char * zTail = 0;
- sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb);
+ sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb);
jbyte * const pBuf = pDb ? s3jni_jbyteArray_bytes(baSql) : 0;
int rc = SQLITE_ERROR;
@@ -3966,11 +4344,11 @@ static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb,
#if !defined(SQLITE_ENABLE_PREUPDATE_HOOK)
/* We need no-op impls for preupdate_{count,depth,blobwrite}() */
-S3JniApi(sqlite3_preupdate_blobwrite(),int,1preupdate_1blobwrite)(
+S3JniApi(sqlite3_preupdate_blobwrite(),jint,1preupdate_1blobwrite)(
JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
-S3JniApi(sqlite3_preupdate_count(),int,1preupdate_1count)(
+S3JniApi(sqlite3_preupdate_count(),jint,1preupdate_1count)(
JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
-S3JniApi(sqlite3_preupdate_depth(),int,1preupdate_1depth)(
+S3JniApi(sqlite3_preupdate_depth(),jint,1preupdate_1depth)(
JniArgsEnvClass, jlong jDb){ return SQLITE_MISUSE; }
#endif /* !SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -4065,7 +4443,7 @@ S3JniApi(sqlite3_preupdate_hook(),jobject,1preupdate_1hook)(
static int s3jni_preupdate_newold(JNIEnv * const env, int isNew, jlong jpDb,
jint iCol, jobject jOut){
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
- sqlite3 * const pDb = S3JniLongPtr_sqlite3(jpDb);
+ sqlite3 * const pDb = LongPtrGet_sqlite3(jpDb);
int rc = SQLITE_MISUSE;
if( pDb ){
sqlite3_value * pOut = 0;
@@ -4286,7 +4664,7 @@ S3JniApi(sqlite3_result_double(),void,1result_1double)(
}
S3JniApi(sqlite3_result_error(),void,1result_1error)(
- JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, int eTextRep
+ JniArgsEnvClass, jobject jpCx, jbyteArray baMsg, jint eTextRep
){
const char * zUnspecified = "Unspecified error.";
jsize const baLen = (*env)->GetArrayLength(env, baMsg);
@@ -4351,7 +4729,7 @@ S3JniApi(sqlite3_result_java_object(),void,1result_1java_1object)(
jobject const rjv = S3JniRefGlobal(v);
if( rjv ){
sqlite3_result_pointer(pCx, rjv,
- ResultJavaValuePtrStr, S3Jni_jobject_finalizer);
+ s3jni__value_jref_key, S3Jni_jobject_finalizer);
}else{
sqlite3_result_error_nomem(PtrGet_sqlite3_context(jpCx));
}
@@ -4360,12 +4738,53 @@ S3JniApi(sqlite3_result_java_object(),void,1result_1java_1object)(
}
}
+S3JniApi(sqlite3_result_nio_buffer(),void,1result_1nio_1buffer)(
+ JniArgsEnvClass, jobject jpCtx, jobject jBuffer,
+ jint iOffset, jint iN
+){
+ sqlite3_context * pCx = PtrGet_sqlite3_context(jpCtx);
+ int rc;
+ S3JniNioArgs args;
+ if( !pCx ){
+ return;
+ }else if( !SJG.g.byteBuffer.klazz ){
+ sqlite3_result_error(
+ pCx, "This JVM does not support JNI access to ByteBuffers.", -1
+ );
+ return;
+ }
+ rc = s3jni_setup_nio_args(env, &args, jBuffer, iOffset, iN);
+ if(rc){
+ if( iOffset<0 ){
+ sqlite3_result_error(pCx, "Start index may not be negative.", -1);
+ }else if( SQLITE_TOOBIG==rc ){
+ sqlite3_result_error_toobig(pCx);
+ }else{
+ sqlite3_result_error(
+ pCx, "Invalid arguments to sqlite3_result_nio_buffer().", -1
+ );
+ }
+ }else if( !args.pStart || !args.nOut ){
+ sqlite3_result_null(pCx);
+ }else{
+ sqlite3_result_blob(pCx, args.pStart, args.nOut, SQLITE_TRANSIENT);
+ }
+}
+
+
S3JniApi(sqlite3_result_null(),void,1result_1null)(
JniArgsEnvClass, jobject jpCx
){
sqlite3_result_null(PtrGet_sqlite3_context(jpCx));
}
+S3JniApi(sqlite3_result_subtype(),void,1result_1subtype)(
+ JniArgsEnvClass, jobject jpCx, jint v
+){
+ sqlite3_result_subtype(PtrGet_sqlite3_context(jpCx), (unsigned int)v);
+}
+
+
S3JniApi(sqlite3_result_text(),void,1result_1text)(
JniArgsEnvClass, jobject jpCx, jbyteArray jBa, jint nMax
){
@@ -4539,20 +4958,8 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
S3JniEnv_uncache( SJG.envCache.aHead->env );
}
} S3JniEnv_mutex_leave;
-#if 0
- /*
- ** Is automatically closing any still-open dbs a good idea? We will
- ** get rid of the perDb list once sqlite3 gets a per-db client
- ** state, at which point we won't have a central list of databases
- ** to close.
- */
- S3JniDb_mutex_enter;
- while( SJG.perDb.pHead ){
- s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
- }
- S3JniDb_mutex_leave;
-#endif
- /* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
+ /* Do not clear S3JniGlobal.jvm or S3JniGlobal.g: it's legal to
+ ** restart the lib. */
return sqlite3_shutdown();
}
@@ -4594,7 +5001,7 @@ static int s3jni_strlike_glob(int isLike, JNIEnv *const env,
jbyteArray baG, jbyteArray baT, jint escLike){
int rc = 0;
jbyte * const pG = s3jni_jbyteArray_bytes(baG);
- jbyte * const pT = pG ? s3jni_jbyteArray_bytes(baT) : 0;
+ jbyte * const pT = s3jni_jbyteArray_bytes(baT);
/* Note that we're relying on the byte arrays having been
NUL-terminated on the Java side. */
@@ -4633,13 +5040,13 @@ S3JniApi(sqlite3_sql(),jstring,1sql)(
}
S3JniApi(sqlite3_step(),jint,1step)(
- JniArgsEnvClass,jobject jStmt
+ JniArgsEnvClass, jlong jpStmt
){
- sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jStmt);
+ sqlite3_stmt * const pStmt = LongPtrGet_sqlite3_stmt(jpStmt);
return pStmt ? (jint)sqlite3_step(pStmt) : (jint)SQLITE_MISUSE;
}
-S3JniApi(sqlite3_table_column_metadata(),int,1table_1column_1metadata)(
+S3JniApi(sqlite3_table_column_metadata(),jint,1table_1column_1metadata)(
JniArgsEnvClass, jobject jDb, jstring jDbName, jstring jTableName,
jstring jColumnName, jobject jDataType, jobject jCollSeq, jobject jNotNull,
jobject jPrimaryKey, jobject jAutoinc
@@ -4815,7 +5222,7 @@ S3JniApi(sqlite3_update_hook(),jobject,1update_1hook)(
S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
const jbyte * pBytes = sv ? sqlite3_value_blob(sv) : 0;
int const nLen = pBytes ? sqlite3_value_bytes(sv) : 0;
@@ -4825,17 +5232,17 @@ S3JniApi(sqlite3_value_blob(),jbyteArray,1value_1blob)(
: NULL;
}
-S3JniApi(sqlite3_value_bytes(),int,1value_1bytes)(
+S3JniApi(sqlite3_value_bytes(),jint,1value_1bytes)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return sv ? sqlite3_value_bytes(sv) : 0;
}
-S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)(
+S3JniApi(sqlite3_value_bytes16(),jint,1value_1bytes16)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return sv ? sqlite3_value_bytes16(sv) : 0;
}
@@ -4843,7 +5250,7 @@ S3JniApi(sqlite3_value_bytes16(),int,1value_1bytes16)(
S3JniApi(sqlite3_value_double(),jdouble,1value_1double)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return (jdouble) (sv ? sqlite3_value_double(sv) : 0.0);
}
@@ -4851,7 +5258,7 @@ S3JniApi(sqlite3_value_double(),jdouble,1value_1double)(
S3JniApi(sqlite3_value_dup(),jobject,1value_1dup)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
sqlite3_value * const sd = sv ? sqlite3_value_dup(sv) : 0;
jobject rv = sd ? new_java_sqlite3_value(env, sd) : 0;
if( sd && !rv ) {
@@ -4864,7 +5271,7 @@ S3JniApi(sqlite3_value_dup(),jobject,1value_1dup)(
S3JniApi(sqlite3_value_free(),void,1value_1free)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
if( sv ){
sqlite3_value_free(sv);
}
@@ -4873,30 +5280,45 @@ S3JniApi(sqlite3_value_free(),void,1value_1free)(
S3JniApi(sqlite3_value_int(),jint,1value_1int)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return (jint) (sv ? sqlite3_value_int(sv) : 0);
}
S3JniApi(sqlite3_value_int64(),jlong,1value_1int64)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return (jlong) (sv ? sqlite3_value_int64(sv) : 0LL);
}
S3JniApi(sqlite3_value_java_object(),jobject,1value_1java_1object)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
return sv
- ? sqlite3_value_pointer(sv, ResultJavaValuePtrStr)
+ ? sqlite3_value_pointer(sv, s3jni__value_jref_key)
: 0;
}
+S3JniApi(sqlite3_value_nio_buffer(),jobject,1value_1nio_1buffer)(
+ JniArgsEnvClass, jobject jVal
+){
+ sqlite3_value * const sv = PtrGet_sqlite3_value(jVal);
+ jobject rv = 0;
+ if( sv ){
+ const void * const p = sqlite3_value_blob(sv);
+ if( p ){
+ const int n = sqlite3_value_bytes(sv);
+ rv = s3jni__blob_to_ByteBuffer(env, p, n);
+ }
+ }
+ return rv;
+}
+
S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0;
int const n = p ? sqlite3_value_bytes(sv) : 0;
return p ? s3jni_new_jbyteArray(p, n) : 0;
@@ -4907,7 +5329,7 @@ S3JniApi(sqlite3_value_text(),jbyteArray,1value_1text)(
S3JniApi(sqlite3_value_text(),jstring,1value_1text)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
const unsigned char * const p = sv ? sqlite3_value_text(sv) : 0;
int const n = p ? sqlite3_value_bytes(sv) : 0;
return p ? s3jni_utf8_to_jstring( (const char *)p, n) : 0;
@@ -4917,7 +5339,7 @@ S3JniApi(sqlite3_value_text(),jstring,1value_1text)(
S3JniApi(sqlite3_value_text16(),jstring,1value_1text16)(
JniArgsEnvClass, jlong jpSVal
){
- sqlite3_value * const sv = S3JniLongPtr_sqlite3_value(jpSVal);
+ sqlite3_value * const sv = LongPtrGet_sqlite3_value(jpSVal);
const int n = sv ? sqlite3_value_bytes16(sv) : 0;
const void * const p = sv ? sqlite3_value_text16(sv) : 0;
return p ? s3jni_text16_to_jstring(env, p, n) : 0;
@@ -5499,7 +5921,7 @@ JniDeclFtsXA(jlong,xRowid)(JniArgsEnvObj,jobject jCtx){
return (jlong)ext->xRowid(PtrGet_Fts5Context(jCtx));
}
-JniDeclFtsXA(int,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
+JniDeclFtsXA(jint,xSetAuxdata)(JniArgsEnvObj,jobject jCtx, jobject jAux){
Fts5ExtDecl;
int rc;
S3JniFts5AuxData * pAux;
@@ -5893,6 +6315,28 @@ Java_org_sqlite_jni_capi_CApi_init(JniArgsEnvClass){
s3jni_oom_fatal( SJG.metrics.mutex );
#endif
+ {
+ /* Test whether this JVM supports direct memory access via
+ ByteBuffer. */
+ unsigned char buf[16] = {0};
+ jobject bb = (*env)->NewDirectByteBuffer(env, buf, 16);
+ if( bb ){
+ SJG.g.byteBuffer.klazz = S3JniRefGlobal((*env)->GetObjectClass(env, bb));
+ SJG.g.byteBuffer.midAlloc = (*env)->GetStaticMethodID(
+ env, SJG.g.byteBuffer.klazz, "allocateDirect", "(I)Ljava/nio/ByteBuffer;"
+ );
+ S3JniExceptionIsFatal("Error getting ByteBuffer.allocateDirect() method.");
+ SJG.g.byteBuffer.midLimit = (*env)->GetMethodID(
+ env, SJG.g.byteBuffer.klazz, "limit", "()I"
+ );
+ S3JniExceptionIsFatal("Error getting ByteBuffer.limit() method.");
+ S3JniUnrefLocal(bb);
+ }else{
+ SJG.g.byteBuffer.klazz = 0;
+ SJG.g.byteBuffer.midAlloc = 0;
+ }
+ }
+
sqlite3_shutdown()
/* So that it becomes legal for Java-level code to call
** sqlite3_config(). */;
diff --git a/ext/jni/src/c/sqlite3-jni.h b/ext/jni/src/c/sqlite3-jni.h
index bf6df7ac94..082a202122 100644
--- a/ext/jni/src/c/sqlite3-jni.h
+++ b/ext/jni/src/c/sqlite3-jni.h
@@ -427,8 +427,6 @@ extern "C" {
#define org_sqlite_jni_capi_CApi_SQLITE_OPEN_EXRESCODE 33554432L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT 1L
-#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE
-#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE 2L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB 4L
#undef org_sqlite_jni_capi_CApi_SQLITE_OK
@@ -707,8 +705,12 @@ extern "C" {
#define org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC 2048L
#undef org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY
#define org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY 524288L
+#undef org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE
+#define org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE 1048576L
#undef org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS
#define org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS 2097152L
+#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE
+#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE
#define org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_EQ
@@ -775,6 +777,22 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_init
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_1thread
(JNIEnv *, jclass);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_jni_supports_nio
+ * Signature: ()Z
+ */
+JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
+ (JNIEnv *, jclass);
+
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_jni_db_error
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1db_1error
+ (JNIEnv *, jclass, jobject, jint, jstring);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_aggregate_context
@@ -871,6 +889,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1int64
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1java_1object
(JNIEnv *, jclass, jlong, jint, jobject);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_bind_nio_buffer
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;ILjava/nio/ByteBuffer;II)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1nio_1buffer
+ (JNIEnv *, jclass, jobject, jint, jobject, jint, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_bind_null
@@ -975,6 +1001,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1open
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read
(JNIEnv *, jclass, jlong, jbyteArray, jint);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_blob_read_nio_buffer
+ * Signature: (JILjava/nio/ByteBuffer;II)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read_1nio_1buffer
+ (JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_blob_reopen
@@ -991,6 +1025,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1reopen
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write
(JNIEnv *, jclass, jlong, jbyteArray, jint);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_blob_write_nio_buffer
+ * Signature: (JILjava/nio/ByteBuffer;II)I
+ */
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write_1nio_1buffer
+ (JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_busy_handler
@@ -1087,6 +1129,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1bytes16
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1count
(JNIEnv *, jclass, jlong);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_column_database_name
+ * Signature: (JI)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
+ (JNIEnv *, jclass, jlong, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_decltype
@@ -1119,6 +1169,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int
JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int64
(JNIEnv *, jclass, jobject, jint);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_column_java_object
+ * Signature: (JI)Ljava/lang/Object;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1java_1object
+ (JNIEnv *, jclass, jlong, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_name
@@ -1129,11 +1187,11 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1name
/*
* Class: org_sqlite_jni_capi_CApi
- * Method: sqlite3_column_database_name
- * Signature: (JI)Ljava/lang/String;
+ * Method: sqlite3_column_nio_buffer
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;I)Ljava/nio/ByteBuffer;
*/
-JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
- (JNIEnv *, jclass, jlong, jint);
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1nio_1buffer
+ (JNIEnv *, jclass, jobject, jint);
/*
* Class: org_sqlite_jni_capi_CApi
@@ -1225,26 +1283,26 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
/*
* Class: org_sqlite_jni_capi_CApi
- * Method: sqlite3_config
+ * Method: sqlite3_config__enable
* Signature: (I)I
*/
-JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__I
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1enable
(JNIEnv *, jclass, jint);
/*
* Class: org_sqlite_jni_capi_CApi
- * Method: sqlite3_config
- * Signature: (Lorg/sqlite/jni/capi/ConfigSqllogCallback;)I
+ * Method: sqlite3_config__CONFIG_LOG
+ * Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
*/
-JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigSqllogCallback_2
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1CONFIG_1LOG
(JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
- * Method: sqlite3_config
- * Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
+ * Method: sqlite3_config__SQLLOG
+ * Signature: (Lorg/sqlite/jni/capi/ConfigSqlLogCallback;)I
*/
-JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigLogCallback_2
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1SQLLOG
(JNIEnv *, jclass, jobject);
/*
@@ -1394,9 +1452,9 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1errcode
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_extended_result_codes
- * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)Z
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)I
*/
-JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
+JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
(JNIEnv *, jclass, jobject, jboolean);
/*
@@ -1679,14 +1737,6 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error_1nom
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error_1code
(JNIEnv *, jclass, jobject, jint);
-/*
- * Class: org_sqlite_jni_capi_CApi
- * Method: sqlite3_result_null
- * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
- */
-JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
- (JNIEnv *, jclass, jobject);
-
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_int
@@ -1711,6 +1761,30 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1int64
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1java_1object
(JNIEnv *, jclass, jobject, jobject);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_result_nio_buffer
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Ljava/nio/ByteBuffer;II)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1nio_1buffer
+ (JNIEnv *, jclass, jobject, jobject, jint, jint);
+
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_result_null
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
+ (JNIEnv *, jclass, jobject);
+
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_result_subtype
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_context;I)V
+ */
+JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1subtype
+ (JNIEnv *, jclass, jobject, jint);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_value
@@ -1850,10 +1924,10 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1status64
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_step
- * Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;)I
+ * Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1step
- (JNIEnv *, jclass, jobject);
+ (JNIEnv *, jclass, jlong);
/*
* Class: org_sqlite_jni_capi_CApi
@@ -2063,6 +2137,14 @@ JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1int64
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1java_1object
(JNIEnv *, jclass, jlong);
+/*
+ * Class: org_sqlite_jni_capi_CApi
+ * Method: sqlite3_value_nio_buffer
+ * Signature: (Lorg/sqlite/jni/capi/sqlite3_value;)Ljava/nio/ByteBuffer;
+ */
+JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1nio_1buffer
+ (JNIEnv *, jclass, jobject);
+
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_value_nochange
diff --git a/ext/jni/src/org/sqlite/jni/annotation/Experimental.java b/ext/jni/src/org/sqlite/jni/annotation/Experimental.java
new file mode 100644
index 0000000000..190435c858
--- /dev/null
+++ b/ext/jni/src/org/sqlite/jni/annotation/Experimental.java
@@ -0,0 +1,30 @@
+/*
+** 2023-09-27
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file houses the Experimental annotation for the sqlite3 C API.
+*/
+package org.sqlite.jni.annotation;
+import java.lang.annotation.*;
+
+/**
+ This annotation is for flagging methods, constructors, and types
+ which are expressly experimental and subject to any amount of
+ change or outright removal. Client code should not rely on such
+ features.
+*/
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target({
+ ElementType.METHOD,
+ ElementType.CONSTRUCTOR,
+ ElementType.TYPE
+})
+public @interface Experimental{}
diff --git a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java
index 3b4c1c7af1..0c31782f23 100644
--- a/ext/jni/src/org/sqlite/jni/annotation/NotNull.java
+++ b/ext/jni/src/org/sqlite/jni/annotation/NotNull.java
@@ -9,21 +9,22 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file houses the NotNull annotaion for the sqlite3 C API.
+** This file houses the NotNull annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
+import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may not legally be
null or point to closed/finalized C-side resources.
In the case of Java types which map directly to C struct types
- (e.g. {@link org.sqlite.jni.sqlite3}, {@link
- org.sqlite.jni.sqlite3_stmt}, and {@link
- org.sqlite.jni.sqlite3_context}), a closed/finalized resource is
- also considered to be null for purposes this annotation because the
- C-side effect of passing such a handle is the same as if null is
- passed.
+ (e.g. {@link org.sqlite.jni.capi.sqlite3}, {@link
+ org.sqlite.jni.capi.sqlite3_stmt}, and {@link
+ org.sqlite.jni.capi.sqlite3_context}), a closed/finalized resource
+ is also considered to be null for purposes this annotation because
+ the C-side effect of passing such a handle is the same as if null
+ is passed.
When used in the context of Java interfaces which are called
from the C APIs, this annotation communicates that the C API will
@@ -31,12 +32,23 @@
Passing a null, for this annotation's definition of null, for
any parameter marked with this annoation specifically invokes
- undefined behavior.
+ undefined behavior (see below).
Passing 0 (i.e. C NULL) or a negative value for any long-type
parameter marked with this annoation specifically invokes undefined
- behavior. Such values are treated as C pointers in the JNI
- layer.
+ behavior (see below). Such values are treated as C pointers in the
+ JNI layer.
+
+
Undefined behaviour: the JNI build uses the {@code
+ SQLITE_ENABLE_API_ARMOR} build flag, meaning that the C code
+ invoked with invalid NULL pointers and the like will not invoke
+ undefined behavior in the conventional C sense, but may, for
+ example, return result codes which are not documented for the
+ affected APIs or may otherwise behave unpredictably. In no known
+ cases will such arguments result in C-level code dereferencing a
+ NULL pointer or accessing out-of-bounds (or otherwise invalid)
+ memory. In other words, they may cause unexpected behavior but
+ should never cause an outright crash or security issue.
Note that the C-style API does not throw any exceptions on its
own because it has a no-throw policy in order to retain its C-style
@@ -48,12 +60,12 @@ semantics, but it may trigger NullPointerExceptions (or similar) if
code.
This annotation is solely for the use by the classes in the
- org.sqlite package and subpackages, but is made public so that
+ org.sqlite.jni package and subpackages, but is made public so that
javadoc will link to it from the annotated functions. It is not
part of the public API and client-level code must not rely on
it.
*/
-@java.lang.annotation.Documented
-@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
-@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.PARAMETER)
public @interface NotNull{}
diff --git a/ext/jni/src/org/sqlite/jni/annotation/Nullable.java b/ext/jni/src/org/sqlite/jni/annotation/Nullable.java
index ddc8502d67..e3fa30efc9 100644
--- a/ext/jni/src/org/sqlite/jni/annotation/Nullable.java
+++ b/ext/jni/src/org/sqlite/jni/annotation/Nullable.java
@@ -9,9 +9,10 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file houses the Nullable annotaion for the sqlite3 C API.
+** This file houses the Nullable annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
+import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may legally be
@@ -26,7 +27,7 @@
annotated functions. It is not part of the public API and
client-level code must not rely on it.
*/
-@java.lang.annotation.Documented
-@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
-@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.PARAMETER)
public @interface Nullable{}
diff --git a/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java b/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
index 89c4f27421..1fa6c6b805 100644
--- a/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
+++ b/ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java
@@ -42,9 +42,75 @@ If this function throws, it is translated into an sqlite3_result_error().
*/
public void xDestroy() {}
+ /**
+ PerContextState assists aggregate and window functions in
+ managing their accumulator state across calls to the UDF's
+ callbacks.
+
+
T must be of a type which can be legally stored as a value in
+ java.util.HashMap.
+
+
If a given aggregate or window function is called multiple times
+ in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
+ then the clients need some way of knowing which call is which so
+ that they can map their state between their various UDF callbacks
+ and reset it via xFinal(). This class takes care of such
+ mappings.
+
+
This class works by mapping
+ sqlite3_context.getAggregateContext() to a single piece of
+ state, of a client-defined type (the T part of this class), which
+ persists across a "matching set" of the UDF's callbacks.
+
+
This class is a helper providing commonly-needed functionality
+ - it is not required for use with aggregate or window functions.
+ Client UDFs are free to perform such mappings using custom
+ approaches. The provided {@link AggregateFunction} and {@link
+ WindowFunction} classes use this.
+ */
+ public static final class PerContextState {
+ private final java.util.Map> map
+ = new java.util.HashMap<>();
+
+ /**
+ Should be called from a UDF's xStep(), xValue(), and xInverse()
+ methods, passing it that method's first argument and an initial
+ value for the persistent state. If there is currently no
+ mapping for the given context within the map, one is created
+ using the given initial value, else the existing one is used
+ and the 2nd argument is ignored. It returns a ValueHolder
+ which can be used to modify that state directly without
+ requiring that the client update the underlying map's entry.
+
+
The caller is obligated to eventually call
+ takeAggregateState() to clear the mapping.
+ */
+ public ValueHolder getAggregateState(sqlite3_context cx, T initialValue){
+ final Long key = cx.getAggregateContext(true);
+ ValueHolder rc = null==key ? null : map.get(key);
+ if( null==rc ){
+ map.put(key, rc = new ValueHolder<>(initialValue));
+ }
+ return rc;
+ }
+
+ /**
+ Should be called from a UDF's xFinal() method and passed that
+ method's first argument. This function removes the value
+ associated with cx.getAggregateContext() from the map and
+ returns it, returning null if no other UDF method has been
+ called to set up such a mapping. The latter condition will be
+ the case if a UDF is used in a statement which has no result
+ rows.
+ */
+ public T takeAggregateState(sqlite3_context cx){
+ final ValueHolder h = map.remove(cx.getAggregateContext(false));
+ return null==h ? null : h.value;
+ }
+ }
+
/** Per-invocation state for the UDF. */
- private final SQLFunction.PerContextState map =
- new SQLFunction.PerContextState<>();
+ private final PerContextState map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
diff --git a/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java b/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java
index ce7c6fca6d..298e3a5900 100644
--- a/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java
@@ -20,7 +20,8 @@
public interface AuthorizerCallback extends CallbackProxy {
/**
Must function as described for the C-level
- sqlite3_set_authorizer() callback.
+ sqlite3_set_authorizer() callback. If it throws, the error is
+ converted to a db-level error and the exception is suppressed.
*/
int call(int opId, @Nullable String s1, @Nullable String s2,
@Nullable String s3, @Nullable String s4);
diff --git a/ext/jni/src/org/sqlite/jni/capi/CApi.java b/ext/jni/src/org/sqlite/jni/capi/CApi.java
index 302cdb760e..b5d08306e2 100644
--- a/ext/jni/src/org/sqlite/jni/capi/CApi.java
+++ b/ext/jni/src/org/sqlite/jni/capi/CApi.java
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file declares JNI bindings for the sqlite3 C API.
+** This file declares the main JNI bindings for the sqlite3 C API.
*/
package org.sqlite.jni.capi;
import java.nio.charset.StandardCharsets;
@@ -32,15 +32,6 @@
The C-side part can be found in sqlite3-jni.c.
-
This class is package-private in order to keep Java clients from
- having direct access to the low-level C-style APIs, a design
- decision made by Java developers based on the C-style API being
- riddled with opportunities for Java developers to proverbially shoot
- themselves in the foot with. Third-party copies of this code may
- eliminate that guard by simply changing this class from
- package-private to public. Its methods which are intended to be
- exposed that way are all public.
-
Only functions which materially differ from their C counterparts
are documented here, and only those material differences are
documented. The C documentation is otherwise applicable for these
@@ -78,7 +69,7 @@ eliminate that guard by simply changing this class from
NUL-terminated, and conversion to a Java byte array must sometimes
be careful to add one. Functions which take a length do not require
this so long as the length is provided. Search the CApi class
- for "\0" for many examples.
+ for "\0" for examples.
@@ -128,10 +119,38 @@ private static byte[] nulTerminateUtf8(String s){
This routine returns false without side effects if the current
JNIEnv is not cached, else returns true, but this information is
primarily for testing of the JNI bindings and is not information
- which client-level code can use to make any informed decisions.
+ which client-level code can use to make any informed
+ decisions. Its return type and semantics are not considered
+ stable and may change at any time.
*/
public static native boolean sqlite3_java_uncache_thread();
+ /**
+ Returns true if this JVM has JNI-level support for C-level direct
+ memory access using java.nio.ByteBuffer, else returns false.
+ */
+ @Experimental
+ public static native boolean sqlite3_jni_supports_nio();
+
+ /**
+ For internal use only. Sets the given db's error code and
+ (optionally) string. If rc is 0, it defaults to SQLITE_ERROR.
+
+ On success it returns rc. On error it may return a more serious
+ code, such as SQLITE_NOMEM. Returns SQLITE_MISUSE if db is null.
+ */
+ static native int sqlite3_jni_db_error(@NotNull sqlite3 db,
+ int rc, @Nullable String msg);
+
+ /**
+ Convenience overload which uses e.toString() as the error
+ message.
+ */
+ static int sqlite3_jni_db_error(@NotNull sqlite3 db,
+ int rc, @NotNull Exception e){
+ return sqlite3_jni_db_error(db, rc, e.toString());
+ }
+
//////////////////////////////////////////////////////////////////////
// Maintenance reminder: please keep the sqlite3_.... functions
// alphabetized. The SQLITE_... values. on the other hand, are
@@ -173,13 +192,13 @@ auto-extension callback interface is unnecessary here.
*/
public static native int sqlite3_auto_extension(@NotNull AutoExtensionCallback callback);
- static native int sqlite3_backup_finish(@NotNull long ptrToBackup);
+ private static native int sqlite3_backup_finish(@NotNull long ptrToBackup);
public static int sqlite3_backup_finish(@NotNull sqlite3_backup b){
- return sqlite3_backup_finish(b.clearNativePointer());
+ return null==b ? 0 : sqlite3_backup_finish(b.clearNativePointer());
}
- static native sqlite3_backup sqlite3_backup_init(
+ private static native sqlite3_backup sqlite3_backup_init(
@NotNull long ptrToDbDest, @NotNull String destTableName,
@NotNull long ptrToDbSrc, @NotNull String srcTableName
);
@@ -192,25 +211,25 @@ public static sqlite3_backup sqlite3_backup_init(
dbSrc.getNativePointer(), srcTableName );
}
- static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup);
+ private static native int sqlite3_backup_pagecount(@NotNull long ptrToBackup);
public static int sqlite3_backup_pagecount(@NotNull sqlite3_backup b){
return sqlite3_backup_pagecount(b.getNativePointer());
}
- static native int sqlite3_backup_remaining(@NotNull long ptrToBackup);
+ private static native int sqlite3_backup_remaining(@NotNull long ptrToBackup);
public static int sqlite3_backup_remaining(@NotNull sqlite3_backup b){
return sqlite3_backup_remaining(b.getNativePointer());
}
- static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage);
+ private static native int sqlite3_backup_step(@NotNull long ptrToBackup, int nPage);
public static int sqlite3_backup_step(@NotNull sqlite3_backup b, int nPage){
return sqlite3_backup_step(b.getNativePointer(), nPage);
}
- static native int sqlite3_bind_blob(
+ private static native int sqlite3_bind_blob(
@NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int n
);
@@ -218,7 +237,7 @@ static native int sqlite3_bind_blob(
If n is negative, SQLITE_MISUSE is returned. If n>data.length
then n is silently truncated to data.length.
*/
- static int sqlite3_bind_blob(
+ public static int sqlite3_bind_blob(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data, int n
){
return sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, n);
@@ -232,7 +251,31 @@ public static int sqlite3_bind_blob(
: sqlite3_bind_blob(stmt.getNativePointer(), ndx, data, data.length);
}
- static native int sqlite3_bind_double(
+ /**
+ Convenience overload which is a simple proxy for
+ sqlite3_bind_nio_buffer().
+ */
+ @Experimental
+ /*public*/ static int sqlite3_bind_blob(
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
+ int begin, int n
+ ){
+ return sqlite3_bind_nio_buffer(stmt, ndx, data, begin, n);
+ }
+
+ /**
+ Convenience overload which is equivalant to passing its arguments
+ to sqlite3_bind_nio_buffer() with the values 0 and -1 for the
+ final two arguments.
+ */
+ @Experimental
+ /*public*/ static int sqlite3_bind_blob(
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
+ ){
+ return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
+ }
+
+ private static native int sqlite3_bind_double(
@NotNull long ptrToStmt, int ndx, double v
);
@@ -242,7 +285,7 @@ public static int sqlite3_bind_double(
return sqlite3_bind_double(stmt.getNativePointer(), ndx, v);
}
- static native int sqlite3_bind_int(
+ private static native int sqlite3_bind_int(
@NotNull long ptrToStmt, int ndx, int v
);
@@ -252,7 +295,7 @@ public static int sqlite3_bind_int(
return sqlite3_bind_int(stmt.getNativePointer(), ndx, v);
}
- static native int sqlite3_bind_int64(
+ private static native int sqlite3_bind_int64(
@NotNull long ptrToStmt, int ndx, long v
);
@@ -260,10 +303,65 @@ public static int sqlite3_bind_int64(@NotNull sqlite3_stmt stmt, int ndx, long v
return sqlite3_bind_int64( stmt.getNativePointer(), ndx, v );
}
- static native int sqlite3_bind_java_object(
+ private static native int sqlite3_bind_java_object(
@NotNull long ptrToStmt, int ndx, @Nullable Object o
);
+ /**
+ Binds the contents of the given buffer object as a blob.
+
+ The byte range of the buffer may be restricted by providing a
+ start index and a number of bytes. beginPos may not be negative.
+ Negative howMany is interpretated as the remainder of the buffer
+ past the given start position, up to the buffer's limit() (as
+ opposed its capacity()).
+
+ If beginPos+howMany would extend past the limit() of the buffer
+ then SQLITE_ERROR is returned.
+
+ If any of the following are true, this function behaves like
+ sqlite3_bind_null(): the buffer is null, beginPos is at or past
+ the end of the buffer, howMany is 0, or the calculated slice of
+ the blob has a length of 0.
+
+ If ndx is out of range, it returns SQLITE_RANGE, as documented
+ for sqlite3_bind_blob(). If beginPos is negative or if
+ sqlite3_jni_supports_nio() returns false then SQLITE_MISUSE is
+ returned. Note that this function is bound (as it were) by the
+ SQLITE_LIMIT_LENGTH constraint and SQLITE_TOOBIG is returned if
+ the resulting slice of the buffer exceeds that limit.
+
+ This function does not modify the buffer's streaming-related
+ cursors.
+
+ If the buffer is modified in a separate thread while this
+ operation is running, results are undefined and will likely
+ result in corruption of the bound data or a segmentation fault.
+
+ Design note: this function should arguably take a java.nio.Buffer
+ instead of ByteBuffer, but it can only operate on "direct"
+ buffers and the only such class offered by Java is (apparently)
+ ByteBuffer.
+
+ @see https://docs.oracle.com/javase/8/docs/api/java/nio/Buffer.html
+ */
+ @Experimental
+ /*public*/ static native int sqlite3_bind_nio_buffer(
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data,
+ int beginPos, int howMany
+ );
+
+ /**
+ Convenience overload which binds the given buffer's entire
+ contents, up to its limit() (as opposed to its capacity()).
+ */
+ @Experimental
+ /*public*/ static int sqlite3_bind_nio_buffer(
+ @NotNull sqlite3_stmt stmt, int ndx, @Nullable java.nio.ByteBuffer data
+ ){
+ return sqlite3_bind_nio_buffer(stmt, ndx, data, 0, -1);
+ }
+
/**
Binds the given object at the given index. If o is null then this behaves like
sqlite3_bind_null().
@@ -276,13 +374,13 @@ public static int sqlite3_bind_java_object(
return sqlite3_bind_java_object(stmt.getNativePointer(), ndx, o);
}
- static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx);
+ private static native int sqlite3_bind_null(@NotNull long ptrToStmt, int ndx);
public static int sqlite3_bind_null(@NotNull sqlite3_stmt stmt, int ndx){
return sqlite3_bind_null(stmt.getNativePointer(), ndx);
}
- static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt);
+ private static native int sqlite3_bind_parameter_count(@NotNull long ptrToStmt);
public static int sqlite3_bind_parameter_count(@NotNull sqlite3_stmt stmt){
return sqlite3_bind_parameter_count(stmt.getNativePointer());
@@ -309,7 +407,7 @@ public static int sqlite3_bind_parameter_index(
return null==utf8 ? 0 : sqlite3_bind_parameter_index(stmt.getNativePointer(), utf8);
}
- static native String sqlite3_bind_parameter_name(
+ private static native String sqlite3_bind_parameter_name(
@NotNull long ptrToStmt, int index
);
@@ -317,7 +415,7 @@ public static String sqlite3_bind_parameter_name(@NotNull sqlite3_stmt stmt, int
return sqlite3_bind_parameter_name(stmt.getNativePointer(), index);
}
- static native int sqlite3_bind_text(
+ private static native int sqlite3_bind_text(
@NotNull long ptrToStmt, int ndx, @Nullable byte[] utf8, int maxBytes
);
@@ -361,7 +459,7 @@ public static int sqlite3_bind_text(
: sqlite3_bind_text(stmt.getNativePointer(), ndx, utf8, utf8.length);
}
- static native int sqlite3_bind_text16(
+ private static native int sqlite3_bind_text16(
@NotNull long ptrToStmt, int ndx, @Nullable byte[] data, int maxBytes
);
@@ -402,7 +500,7 @@ public static int sqlite3_bind_text16(
: sqlite3_bind_text16(stmt.getNativePointer(), ndx, data, data.length);
}
- static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue);
+ private static native int sqlite3_bind_value(@NotNull long ptrToStmt, int ndx, long ptrToValue);
/**
Functions like the C-level sqlite3_bind_value(), or
@@ -413,13 +511,13 @@ public static int sqlite3_bind_value(@NotNull sqlite3_stmt stmt, int ndx, sqlite
null==val ? 0L : val.getNativePointer());
}
- static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n);
+ private static native int sqlite3_bind_zeroblob(@NotNull long ptrToStmt, int ndx, int n);
public static int sqlite3_bind_zeroblob(@NotNull sqlite3_stmt stmt, int ndx, int n){
return sqlite3_bind_zeroblob(stmt.getNativePointer(), ndx, n);
}
- static native int sqlite3_bind_zeroblob64(
+ private static native int sqlite3_bind_zeroblob64(
@NotNull long ptrToStmt, int ndx, long n
);
@@ -427,19 +525,19 @@ public static int sqlite3_bind_zeroblob64(@NotNull sqlite3_stmt stmt, int ndx, l
return sqlite3_bind_zeroblob64(stmt.getNativePointer(), ndx, n);
}
- static native int sqlite3_blob_bytes(@NotNull long ptrToBlob);
+ private static native int sqlite3_blob_bytes(@NotNull long ptrToBlob);
public static int sqlite3_blob_bytes(@NotNull sqlite3_blob blob){
return sqlite3_blob_bytes(blob.getNativePointer());
}
- static native int sqlite3_blob_close(@Nullable long ptrToBlob);
+ private static native int sqlite3_blob_close(@Nullable long ptrToBlob);
public static int sqlite3_blob_close(@Nullable sqlite3_blob blob){
- return sqlite3_blob_close(blob.clearNativePointer());
+ return null==blob ? 0 : sqlite3_blob_close(blob.clearNativePointer());
}
- static native int sqlite3_blob_open(
+ private static native int sqlite3_blob_open(
@NotNull long ptrToDb, @NotNull String dbName,
@NotNull String tableName, @NotNull String columnName,
long iRow, int flags, @NotNull OutputPointer.sqlite3_blob out
@@ -467,17 +565,125 @@ public static sqlite3_blob sqlite3_blob_open(
return out.take();
};
- static native int sqlite3_blob_read(
- @NotNull long ptrToBlob, @NotNull byte[] target, int iOffset
+ private static native int sqlite3_blob_read(
+ @NotNull long ptrToBlob, @NotNull byte[] target, int srcOffset
);
+ /**
+ As per C's sqlite3_blob_read(), but writes its output to the
+ given byte array. Note that the final argument is the offset of
+ the source buffer, not the target array.
+ */
public static int sqlite3_blob_read(
- @NotNull sqlite3_blob b, @NotNull byte[] target, int iOffset
+ @NotNull sqlite3_blob src, @NotNull byte[] target, int srcOffset
){
- return sqlite3_blob_read(b.getNativePointer(), target, iOffset);
+ return sqlite3_blob_read(src.getNativePointer(), target, srcOffset);
}
- static native int sqlite3_blob_reopen(
+ /**
+ An internal level of indirection.
+ */
+ @Experimental
+ private static native int sqlite3_blob_read_nio_buffer(
+ @NotNull long ptrToBlob, int srcOffset,
+ @NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
+ );
+
+ /**
+ Reads howMany bytes from offset srcOffset of src into position
+ tgtOffset of tgt.
+
+ Returns SQLITE_MISUSE if src is null, tgt is null, or
+ sqlite3_jni_supports_nio() returns false. Returns SQLITE_ERROR if
+ howMany or either offset are negative. If argument validation
+ succeeds, it returns the result of the underlying call to
+ sqlite3_blob_read() (0 on success).
+ */
+ @Experimental
+ /*public*/ static int sqlite3_blob_read_nio_buffer(
+ @NotNull sqlite3_blob src, int srcOffset,
+ @NotNull java.nio.ByteBuffer tgt, int tgtOffset, int howMany
+ ){
+ return (JNI_SUPPORTS_NIO && src!=null && tgt!=null)
+ ? sqlite3_blob_read_nio_buffer(
+ src.getNativePointer(), srcOffset, tgt, tgtOffset, howMany
+ )
+ : SQLITE_MISUSE;
+ }
+
+ /**
+ Convenience overload which reads howMany bytes from position
+ srcOffset of src and returns the result as a new ByteBuffer.
+
+ srcOffset may not be negative. If howMany is negative, it is
+ treated as all bytes following srcOffset.
+
+ Returns null if sqlite3_jni_supports_nio(), any arguments are
+ invalid, if the number of bytes to read is 0 or is larger than
+ the src blob, or the underlying call to sqlite3_blob_read() fails
+ for any reason.
+ */
+ @Experimental
+ /*public*/ static java.nio.ByteBuffer sqlite3_blob_read_nio_buffer(
+ @NotNull sqlite3_blob src, int srcOffset, int howMany
+ ){
+ if( !JNI_SUPPORTS_NIO || src==null ) return null;
+ else if( srcOffset<0 ) return null;
+ final int nB = sqlite3_blob_bytes(src);
+ if( srcOffset>=nB ) return null;
+ else if( howMany<0 ) howMany = nB - srcOffset;
+ if( srcOffset + howMany > nB ) return null;
+ final java.nio.ByteBuffer tgt =
+ java.nio.ByteBuffer.allocateDirect(howMany);
+ final int rc = sqlite3_blob_read_nio_buffer(
+ src.getNativePointer(), srcOffset, tgt, 0, howMany
+ );
+ return 0==rc ? tgt : null;
+ }
+
+ /**
+ Overload alias for sqlite3_blob_read_nio_buffer().
+ */
+ @Experimental
+ /*public*/ static int sqlite3_blob_read(
+ @NotNull sqlite3_blob src, int srcOffset,
+ @NotNull java.nio.ByteBuffer tgt,
+ int tgtOffset, int howMany
+ ){
+ return sqlite3_blob_read_nio_buffer(
+ src, srcOffset, tgt, tgtOffset, howMany
+ );
+ }
+
+ /**
+ Convenience overload which uses 0 for both src and tgt offsets
+ and reads a number of bytes equal to the smaller of
+ sqlite3_blob_bytes(src) and tgt.limit().
+
+ On success it sets tgt.limit() to the number of bytes read. On
+ error, tgt.limit() is not modified.
+
+ Returns 0 on success. Returns SQLITE_MISUSE is either argument is
+ null or sqlite3_jni_supports_nio() returns false. Else it returns
+ the result of the underlying call to sqlite3_blob_read().
+ */
+ @Experimental
+ /*public*/ static int sqlite3_blob_read(
+ @NotNull sqlite3_blob src,
+ @NotNull java.nio.ByteBuffer tgt
+ ){
+ if(!JNI_SUPPORTS_NIO || src==null || tgt==null) return SQLITE_MISUSE;
+ final int nSrc = sqlite3_blob_bytes(src);
+ final int nTgt = tgt.limit();
+ final int nRead = nTgt T sqlite3_column_java_object(
+ @NotNull sqlite3_stmt stmt, int ndx, @NotNull Class type
+ ){
+ final Object o = sqlite3_column_java_object(stmt, ndx);
+ return type.isInstance(o) ? (T)o : null;
}
- static native String sqlite3_column_database_name(@NotNull long ptrToStmt, int ndx);
+ private static native String sqlite3_column_name(@NotNull long ptrToStmt, int ndx);
- public static String sqlite3_column_database_name(@NotNull sqlite3_stmt stmt, int ndx){
- return sqlite3_column_database_name(stmt.getNativePointer(), ndx);
+ public static String sqlite3_column_name(@NotNull sqlite3_stmt stmt, int ndx){
+ return sqlite3_column_name(stmt.getNativePointer(), ndx);
}
- static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);
+ /**
+ A variant of sqlite3_column_blob() which returns the blob as a
+ ByteBuffer object. Returns null if its argument is null, if
+ sqlite3_jni_supports_nio() is false, or if sqlite3_column_blob()
+ would return null for the same inputs.
+ */
+ @Experimental
+ /*public*/ static native java.nio.ByteBuffer sqlite3_column_nio_buffer(
+ @NotNull sqlite3_stmt stmt, int ndx
+ );
+ private static native String sqlite3_column_origin_name(@NotNull long ptrToStmt, int ndx);
+
+ /**
+ Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
+ */
public static String sqlite3_column_origin_name(@NotNull sqlite3_stmt stmt, int ndx){
return sqlite3_column_origin_name(stmt.getNativePointer(), ndx);
}
- static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx);
+ private static native String sqlite3_column_table_name(@NotNull long ptrToStmt, int ndx);
+ /**
+ Only available if built with SQLITE_ENABLE_COLUMN_METADATA.
+ */
public static String sqlite3_column_table_name(@NotNull sqlite3_stmt stmt, int ndx){
return sqlite3_column_table_name(stmt.getNativePointer(), ndx);
}
@@ -672,7 +1001,7 @@ public static native String sqlite3_column_text16(
// return rv;
// }
- static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx);
+ private static native int sqlite3_column_type(@NotNull long ptrToStmt, int ndx);
public static int sqlite3_column_type(@NotNull sqlite3_stmt stmt, int ndx){
return sqlite3_column_type(stmt.getNativePointer(), ndx);
@@ -682,7 +1011,7 @@ public static native sqlite3_value sqlite3_column_value(
@NotNull sqlite3_stmt stmt, int ndx
);
- static native int sqlite3_collation_needed(
+ private static native int sqlite3_collation_needed(
@NotNull long ptrToDb, @Nullable CollationNeededCallback callback
);
@@ -696,7 +1025,7 @@ public static int sqlite3_collation_needed(
return sqlite3_collation_needed(db.getNativePointer(), callback);
}
- static native CommitHookCallback sqlite3_commit_hook(
+ private static native CommitHookCallback sqlite3_commit_hook(
@NotNull long ptrToDb, @Nullable CommitHookCallback hook
);
@@ -726,6 +1055,24 @@ public static int sqlite3_complete(@NotNull String sql){
return sqlite3_complete( nulTerminateUtf8(sql) );
}
+ /**
+ Internal level of indirection for sqlite3_config(int).
+ */
+ private static native int sqlite3_config__enable(int op);
+
+ /**
+ Internal level of indirection for sqlite3_config(ConfigLogCallback).
+ */
+ private static native int sqlite3_config__CONFIG_LOG(
+ @Nullable ConfigLogCallback logger
+ );
+
+ /**
+ Internal level of indirection for sqlite3_config(ConfigSqlLogCallback).
+ */
+ private static native int sqlite3_config__SQLLOG(
+ @Nullable ConfigSqlLogCallback logger
+ );
/**
Works like in the C API with the exception that it only supports
@@ -742,12 +1089,14 @@
Note that sqlite3_config() is not threadsafe with regards to
the rest of the library. This must not be called when any other
library APIs are being called.
*/
- public static native int sqlite3_config(int op);
+ public static int sqlite3_config(int op){
+ return sqlite3_config__enable(op);
+ }
/**
If the native library was built with SQLITE_ENABLE_SQLLOG defined
then this acts as a proxy for C's
- sqlite3_config(SQLITE_ENABLE_SQLLOG,...). This sets or clears the
+ sqlite3_config(SQLITE_CONFIG_SQLLOG,...). This sets or clears the
logger. If installation of a logger fails, any previous logger is
retained.
@@ -758,13 +1107,17 @@
Note that sqlite3_config() is not threadsafe with regards to
the rest of the library. This must not be called when any other
library APIs are being called.
*/
- public static native int sqlite3_config( @Nullable ConfigSqllogCallback logger );
+ public static int sqlite3_config( @Nullable ConfigSqlLogCallback logger ){
+ return sqlite3_config__SQLLOG(logger);
+ }
/**
The sqlite3_config() overload for handling the SQLITE_CONFIG_LOG
option.
*/
- public static native int sqlite3_config( @Nullable ConfigLogCallback logger );
+ public static int sqlite3_config( @Nullable ConfigLogCallback logger ){
+ return sqlite3_config__CONFIG_LOG(logger);
+ }
/**
Unlike the C API, this returns null if its argument is
@@ -795,7 +1148,7 @@ public static native int sqlite3_create_function(
int nArg, int eTextRep, @NotNull SQLFunction func
);
- static native int sqlite3_data_count(@NotNull long ptrToStmt);
+ private static native int sqlite3_data_count(@NotNull long ptrToStmt);
public static int sqlite3_data_count(@NotNull sqlite3_stmt stmt){
return sqlite3_data_count(stmt.getNativePointer());
@@ -807,7 +1160,7 @@ Overload for sqlite3_db_config() calls which take (int,int*)
SQLITE_DBCONFIG_... options which uses this call form.
Unlike the C API, this returns SQLITE_MISUSE if its db argument
- are null (as opposed to invoking UB).
+ is null (as opposed to invoking UB).
*/
public static native int sqlite3_db_config(
@NotNull sqlite3 db, int op, int onOff, @Nullable OutputPointer.Int32 out
@@ -830,7 +1183,6 @@ public static String sqlite3_db_name(@NotNull sqlite3 db, int ndx){
return null==db ? null : sqlite3_db_name(db.getNativePointer(), ndx);
}
-
public static native String sqlite3_db_filename(
@NotNull sqlite3 db, @NotNull String dbName
);
@@ -850,7 +1202,7 @@ public static native int sqlite3_db_status(
public static native String sqlite3_errmsg(@NotNull sqlite3 db);
- static native int sqlite3_error_offset(@NotNull long ptrToDb);
+ private static native int sqlite3_error_offset(@NotNull long ptrToDb);
/**
Note that the returned byte offset values assume UTF-8-encoded
@@ -864,17 +1216,17 @@ public static int sqlite3_error_offset(@NotNull sqlite3 db){
public static native String sqlite3_expanded_sql(@NotNull sqlite3_stmt stmt);
- static native int sqlite3_extended_errcode(@NotNull long ptrToDb);
+ private static native int sqlite3_extended_errcode(@NotNull long ptrToDb);
public static int sqlite3_extended_errcode(@NotNull sqlite3 db){
return sqlite3_extended_errcode(db.getNativePointer());
}
- public static native boolean sqlite3_extended_result_codes(
- @NotNull sqlite3 db, boolean onoff
+ public static native int sqlite3_extended_result_codes(
+ @NotNull sqlite3 db, boolean on
);
- static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb);
+ private static native boolean sqlite3_get_autocommit(@NotNull long ptrToDb);
public static boolean sqlite3_get_autocommit(@NotNull sqlite3 db){
return sqlite3_get_autocommit(db.getNativePointer());
@@ -884,7 +1236,7 @@ public static native Object sqlite3_get_auxdata(
@NotNull sqlite3_context cx, int n
);
- static native int sqlite3_finalize(long ptrToStmt);
+ private static native int sqlite3_finalize(long ptrToStmt);
public static int sqlite3_finalize(@NotNull sqlite3_stmt stmt){
return null==stmt ? 0 : sqlite3_finalize(stmt.clearNativePointer());
@@ -1166,9 +1518,13 @@ A convenience wrapper around sqlite3_prepare_v3() which accepts
array. It loops over the input bytes looking for
statements. Each one it finds is passed to p.call(), passing
ownership of it to that function. If p.call() returns 0, looping
- continues, else the loop stops.
+ continues, else the loop stops and p.call()'s result code is
+ returned. If preparation of any given segment fails, looping
+ stops and that result code is returned.
-
If p.call() throws, the exception is propagated.
+
If p.call() throws, the exception is converted to a db-level
+ error and a non-0 code is returned, in order to retain the
+ C-style error semantics of the API.
How each statement is handled, including whether it is finalized
or not, is up to the callback object. e.g. the callback might
@@ -1178,29 +1534,33 @@ A convenience wrapper around sqlite3_prepare_v3() which accepts
*/
public static int sqlite3_prepare_multi(
@NotNull sqlite3 db, @NotNull byte[] sqlUtf8,
- int preFlags,
+ int prepFlags,
@NotNull PrepareMultiCallback p){
final OutputPointer.Int32 oTail = new OutputPointer.Int32();
int pos = 0, n = 1;
byte[] sqlChunk = sqlUtf8;
int rc = 0;
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
- while(0==rc && pos 0){
+ if( pos>0 ){
sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
sqlChunk.length);
}
if( 0==sqlChunk.length ) break;
- rc = sqlite3_prepare_v3(db, sqlChunk, preFlags, outStmt, oTail);
+ rc = sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail);
if( 0!=rc ) break;
pos = oTail.value;
stmt = outStmt.take();
- if( null == stmt ){
- // empty statement was parsed.
+ if( null==stmt ){
+ // empty statement (whitespace/comments)
continue;
}
- rc = p.call(stmt);
+ try{
+ rc = p.call(stmt);
+ }catch(Exception e){
+ rc = sqlite3_jni_db_error( db, SQLITE_ERROR, e );
+ }
}
return rc;
}
@@ -1256,7 +1616,7 @@ public static int sqlite3_prepare_multi(
return sqlite3_prepare_multi(db, sql, 0, p);
}
- static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb);
+ private static native int sqlite3_preupdate_blobwrite(@NotNull long ptrToDb);
/**
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
@@ -1267,7 +1627,7 @@ public static int sqlite3_preupdate_blobwrite(@NotNull sqlite3 db){
return sqlite3_preupdate_blobwrite(db.getNativePointer());
}
- static native int sqlite3_preupdate_count(@NotNull long ptrToDb);
+ private static native int sqlite3_preupdate_count(@NotNull long ptrToDb);
/**
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
@@ -1278,7 +1638,7 @@ public static int sqlite3_preupdate_count(@NotNull sqlite3 db){
return sqlite3_preupdate_count(db.getNativePointer());
}
- static native int sqlite3_preupdate_depth(@NotNull long ptrToDb);
+ private static native int sqlite3_preupdate_depth(@NotNull long ptrToDb);
/**
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined, this
@@ -1289,7 +1649,7 @@ public static int sqlite3_preupdate_depth(@NotNull sqlite3 db){
return sqlite3_preupdate_depth(db.getNativePointer());
}
- static native PreupdateHookCallback sqlite3_preupdate_hook(
+ private static native PreupdateHookCallback sqlite3_preupdate_hook(
@NotNull long ptrToDb, @Nullable PreupdateHookCallback hook
);
@@ -1304,13 +1664,22 @@ public static PreupdateHookCallback sqlite3_preupdate_hook(
return sqlite3_preupdate_hook(db.getNativePointer(), hook);
}
- static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col,
+ private static native int sqlite3_preupdate_new(@NotNull long ptrToDb, int col,
@NotNull OutputPointer.sqlite3_value out);
/**
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
this acts as a proxy for C's sqlite3_preupdate_new(), else it
returns SQLITE_MISUSE with no side effects.
+
+ WARNING: client code _must not_ hold a reference to the returned
+ sqlite3_value object beyond the scope of the preupdate hook in
+ which this function is called. Doing so will leave the client
+ holding a stale pointer, the address of which could point to
+ anything at all after the pre-update hook is complete. This API
+ has no way to record such objects and clear/invalidate them at
+ the end of a pre-update hook. We "could" add infrastructure to do
+ so, but would require significant levels of bookkeeping.
*/
public static int sqlite3_preupdate_new(@NotNull sqlite3 db, int col,
@NotNull OutputPointer.sqlite3_value out){
@@ -1327,13 +1696,16 @@ public static sqlite3_value sqlite3_preupdate_new(@NotNull sqlite3 db, int col){
return out.take();
}
- static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col,
+ private static native int sqlite3_preupdate_old(@NotNull long ptrToDb, int col,
@NotNull OutputPointer.sqlite3_value out);
/**
If the C API was built with SQLITE_ENABLE_PREUPDATE_HOOK defined,
this acts as a proxy for C's sqlite3_preupdate_old(), else it
returns SQLITE_MISUSE with no side effects.
+
+ WARNING: see warning in sqlite3_preupdate_new() regarding the
+ potential for stale sqlite3_value handles.
*/
public static int sqlite3_preupdate_old(@NotNull sqlite3 db, int col,
@NotNull OutputPointer.sqlite3_value out){
@@ -1378,7 +1750,7 @@ The main sqlite3_result_error() impl of which all others are
results in the C-level sqlite3_result_error() being called with a
complaint about the invalid argument.
*/
- static native void sqlite3_result_error(
+ private static native void sqlite3_result_error(
@NotNull sqlite3_context cx, @NotNull byte[] msg, int eTextRep
);
@@ -1432,10 +1804,6 @@ public static native void sqlite3_result_error_code(
@NotNull sqlite3_context cx, int c
);
- public static native void sqlite3_result_null(
- @NotNull sqlite3_context cx
- );
-
public static native void sqlite3_result_int(
@NotNull sqlite3_context cx, int v
);
@@ -1454,9 +1822,6 @@ but that function is not exposed to JNI because (A)
cross-language semantic mismatch and (B) Java doesn't need that
argument for its intended purpose (type safety).
-
Note that there is no sqlite3_column_java_object(), as the
- C-level API has no sqlite3_column_pointer() to proxy.
-
@see #sqlite3_value_java_object
@see #sqlite3_bind_java_object
*/
@@ -1464,6 +1829,45 @@ public static native void sqlite3_result_java_object(
@NotNull sqlite3_context cx, @NotNull Object o
);
+ /**
+ Similar to sqlite3_bind_nio_buffer(), this works like
+ sqlite3_result_blob() but accepts a java.nio.ByteBuffer as its
+ input source. See sqlite3_bind_nio_buffer() for the semantics of
+ the second and subsequent arguments.
+
+ If cx is null then this function will silently fail. If
+ sqlite3_jni_supports_nio() returns false or iBegin is negative,
+ an error result is set. If (begin+n) extends beyond the end of
+ the buffer, it is silently truncated to fit.
+
+ If any of the following apply, this function behaves like
+ sqlite3_result_null(): the blob is null, the resulting slice of
+ the blob is empty.
+
+ If the resulting slice of the buffer exceeds SQLITE_LIMIT_LENGTH
+ then this function behaves like sqlite3_result_error_toobig().
+ */
+ @Experimental
+ /*public*/ static native void sqlite3_result_nio_buffer(
+ @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
+ int begin, int n
+ );
+
+ /**
+ Convenience overload which uses the whole input object
+ as the result blob content.
+ */
+ @Experimental
+ /*public*/ static void sqlite3_result_nio_buffer(
+ @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
+ ){
+ sqlite3_result_nio_buffer(cx, blob, 0, -1);
+ }
+
+ public static native void sqlite3_result_null(
+ @NotNull sqlite3_context cx
+ );
+
public static void sqlite3_result_set(
@NotNull sqlite3_context cx, @NotNull Boolean v
){
@@ -1524,6 +1928,10 @@ public static void sqlite3_result_set(
else sqlite3_result_blob(cx, blob, blob.length);
}
+ public static native void sqlite3_result_subtype(
+ @NotNull sqlite3_context cx, int val
+ );
+
public static native void sqlite3_result_value(
@NotNull sqlite3_context cx, @NotNull sqlite3_value v
);
@@ -1550,6 +1958,29 @@ public static void sqlite3_result_blob(
sqlite3_result_blob(cx, blob, (int)(null==blob ? 0 : blob.length));
}
+ /**
+ Convenience overload which behaves like
+ sqlite3_result_nio_buffer().
+ */
+ @Experimental
+ /*public*/ static void sqlite3_result_blob(
+ @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob,
+ int begin, int n
+ ){
+ sqlite3_result_nio_buffer(cx, blob, begin, n);
+ }
+
+ /**
+ Convenience overload which behaves like the two-argument overload of
+ sqlite3_result_nio_buffer().
+ */
+ @Experimental
+ /*public*/ static void sqlite3_result_blob(
+ @NotNull sqlite3_context cx, @Nullable java.nio.ByteBuffer blob
+ ){
+ sqlite3_result_nio_buffer(cx, blob);
+ }
+
/**
Binds the given text using C's sqlite3_result_blob64() unless:
@@ -1607,7 +2038,8 @@ public static void sqlite3_result_text(
-
text is null: translates to a call to sqlite3_result_null()
+
text is null: translates to a call to {@link
+ #sqlite3_result_null}
text is too large: translates to a call to
{@link #sqlite3_result_error_toobig}
@@ -1651,7 +2083,7 @@ public static void sqlite3_result_text16(
}
}
- static native RollbackHookCallback sqlite3_rollback_hook(
+ private static native RollbackHookCallback sqlite3_rollback_hook(
@NotNull long ptrToDb, @Nullable RollbackHookCallback hook
);
@@ -1703,20 +2135,24 @@ public static native int sqlite3_status64(
@NotNull OutputPointer.Int64 pHighwater, boolean reset
);
- public static native int sqlite3_step(@NotNull sqlite3_stmt stmt);
+ private static native int sqlite3_step(@NotNull long ptrToStmt);
+
+ public static int sqlite3_step(@NotNull sqlite3_stmt stmt){
+ return null==stmt ? SQLITE_MISUSE : sqlite3_step(stmt.getNativePointer());
+ }
public static native boolean sqlite3_stmt_busy(@NotNull sqlite3_stmt stmt);
- static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op);
+ private static native int sqlite3_stmt_explain(@NotNull long ptrToStmt, int op);
public static int sqlite3_stmt_explain(@NotNull sqlite3_stmt stmt, int op){
- return sqlite3_stmt_explain(stmt.getNativePointer(), op);
+ return null==stmt ? SQLITE_MISUSE : sqlite3_stmt_explain(stmt.getNativePointer(), op);
}
- static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt);
+ private static native int sqlite3_stmt_isexplain(@NotNull long ptrToStmt);
public static int sqlite3_stmt_isexplain(@NotNull sqlite3_stmt stmt){
- return sqlite3_stmt_isexplain(stmt.getNativePointer());
+ return null==stmt ? 0 : sqlite3_stmt_isexplain(stmt.getNativePointer());
}
public static native boolean sqlite3_stmt_readonly(@NotNull sqlite3_stmt stmt);
@@ -1737,7 +2173,7 @@ Internal impl of the public sqlite3_strglob() method. Neither
signature is the public-facing one.
*/
private static native int sqlite3_strglob(
- @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8
+ @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8
);
public static int sqlite3_strglob(
@@ -1751,7 +2187,7 @@ public static int sqlite3_strglob(
The LIKE counterpart of the private sqlite3_strglob() method.
*/
private static native int sqlite3_strlike(
- @NotNull byte[] glob, @NotNull byte[] nullTerminatedUtf8,
+ @NotNull byte[] glob, @NotNull byte[] nulTerminatedUtf8,
int escChar
);
@@ -1763,7 +2199,7 @@ public static int sqlite3_strlike(
(int)escChar);
}
- static native int sqlite3_system_errno(@NotNull long ptrToDb);
+ private static native int sqlite3_system_errno(@NotNull long ptrToDb);
public static int sqlite3_system_errno(@NotNull sqlite3 db){
return sqlite3_system_errno(db.getNativePointer());
@@ -1809,13 +2245,13 @@ public static TableColumnMetadata sqlite3_table_column_metadata(
public static native int sqlite3_threadsafe();
- static native int sqlite3_total_changes(@NotNull long ptrToDb);
+ private static native int sqlite3_total_changes(@NotNull long ptrToDb);
public static int sqlite3_total_changes(@NotNull sqlite3 db){
return sqlite3_total_changes(db.getNativePointer());
}
- static native long sqlite3_total_changes64(@NotNull long ptrToDb);
+ private static native long sqlite3_total_changes64(@NotNull long ptrToDb);
public static long sqlite3_total_changes64(@NotNull sqlite3 db){
return sqlite3_total_changes64(db.getNativePointer());
@@ -1838,7 +2274,7 @@ public static native int sqlite3_txn_state(
@NotNull sqlite3 db, @Nullable String zSchema
);
- static native UpdateHookCallback sqlite3_update_hook(
+ private static native UpdateHookCallback sqlite3_update_hook(
@NotNull long ptrToDb, @Nullable UpdateHookCallback hook
);
@@ -1858,67 +2294,67 @@ public static UpdateHookCallback sqlite3_update_hook(
sqlite3_create_function().
*/
- static native byte[] sqlite3_value_blob(@NotNull long ptrToValue);
+ private static native byte[] sqlite3_value_blob(@NotNull long ptrToValue);
public static byte[] sqlite3_value_blob(@NotNull sqlite3_value v){
return sqlite3_value_blob(v.getNativePointer());
}
- static native int sqlite3_value_bytes(@NotNull long ptrToValue);
+ private static native int sqlite3_value_bytes(@NotNull long ptrToValue);
public static int sqlite3_value_bytes(@NotNull sqlite3_value v){
return sqlite3_value_bytes(v.getNativePointer());
}
- static native int sqlite3_value_bytes16(@NotNull long ptrToValue);
+ private static native int sqlite3_value_bytes16(@NotNull long ptrToValue);
public static int sqlite3_value_bytes16(@NotNull sqlite3_value v){
return sqlite3_value_bytes16(v.getNativePointer());
}
- static native double sqlite3_value_double(@NotNull long ptrToValue);
+ private static native double sqlite3_value_double(@NotNull long ptrToValue);
public static double sqlite3_value_double(@NotNull sqlite3_value v){
return sqlite3_value_double(v.getNativePointer());
}
- static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue);
+ private static native sqlite3_value sqlite3_value_dup(@NotNull long ptrToValue);
public static sqlite3_value sqlite3_value_dup(@NotNull sqlite3_value v){
return sqlite3_value_dup(v.getNativePointer());
}
- static native int sqlite3_value_encoding(@NotNull long ptrToValue);
+ private static native int sqlite3_value_encoding(@NotNull long ptrToValue);
public static int sqlite3_value_encoding(@NotNull sqlite3_value v){
return sqlite3_value_encoding(v.getNativePointer());
}
- static native void sqlite3_value_free(@Nullable long ptrToValue);
+ private static native void sqlite3_value_free(@Nullable long ptrToValue);
public static void sqlite3_value_free(@Nullable sqlite3_value v){
- sqlite3_value_free(v.getNativePointer());
+ if( null!=v ) sqlite3_value_free(v.clearNativePointer());
}
- static native boolean sqlite3_value_frombind(@NotNull long ptrToValue);
+ private static native boolean sqlite3_value_frombind(@NotNull long ptrToValue);
public static boolean sqlite3_value_frombind(@NotNull sqlite3_value v){
return sqlite3_value_frombind(v.getNativePointer());
}
- static native int sqlite3_value_int(@NotNull long ptrToValue);
+ private static native int sqlite3_value_int(@NotNull long ptrToValue);
public static int sqlite3_value_int(@NotNull sqlite3_value v){
return sqlite3_value_int(v.getNativePointer());
}
- static native long sqlite3_value_int64(@NotNull long ptrToValue);
+ private static native long sqlite3_value_int64(@NotNull long ptrToValue);
public static long sqlite3_value_int64(@NotNull sqlite3_value v){
return sqlite3_value_int64(v.getNativePointer());
}
- static native Object sqlite3_value_java_object(@NotNull long ptrToValue);
+ private static native Object sqlite3_value_java_object(@NotNull long ptrToValue);
/**
If the given value was set using {@link
@@ -1938,31 +2374,42 @@ A variant of sqlite3_value_java_object() which returns the
given Class, else it returns null.
*/
@SuppressWarnings("unchecked")
- public static T sqlite3_value_java_casted(@NotNull sqlite3_value v,
+ public static T sqlite3_value_java_object(@NotNull sqlite3_value v,
@NotNull Class type){
final Object o = sqlite3_value_java_object(v);
return type.isInstance(o) ? (T)o : null;
}
- static native int sqlite3_value_nochange(@NotNull long ptrToValue);
+ /**
+ A variant of sqlite3_column_blob() which returns the blob as a
+ ByteBuffer object. Returns null if its argument is null, if
+ sqlite3_jni_supports_nio() is false, or if sqlite3_value_blob()
+ would return null for the same input.
+ */
+ @Experimental
+ /*public*/ static native java.nio.ByteBuffer sqlite3_value_nio_buffer(
+ @NotNull sqlite3_value v
+ );
+
+ private static native int sqlite3_value_nochange(@NotNull long ptrToValue);
public static int sqlite3_value_nochange(@NotNull sqlite3_value v){
return sqlite3_value_nochange(v.getNativePointer());
}
- static native int sqlite3_value_numeric_type(@NotNull long ptrToValue);
+ private static native int sqlite3_value_numeric_type(@NotNull long ptrToValue);
public static int sqlite3_value_numeric_type(@NotNull sqlite3_value v){
return sqlite3_value_numeric_type(v.getNativePointer());
}
- static native int sqlite3_value_subtype(@NotNull long ptrToValue);
+ private static native int sqlite3_value_subtype(@NotNull long ptrToValue);
public static int sqlite3_value_subtype(@NotNull sqlite3_value v){
return sqlite3_value_subtype(v.getNativePointer());
}
- static native byte[] sqlite3_value_text(@NotNull long ptrToValue);
+ private static native byte[] sqlite3_value_text(@NotNull long ptrToValue);
/**
Functions identially to the C API, and this note is just to
@@ -1974,13 +2421,13 @@ public static byte[] sqlite3_value_text(@NotNull sqlite3_value v){
return sqlite3_value_text(v.getNativePointer());
}
- static native String sqlite3_value_text16(@NotNull long ptrToValue);
+ private static native String sqlite3_value_text16(@NotNull long ptrToValue);
public static String sqlite3_value_text16(@NotNull sqlite3_value v){
return sqlite3_value_text16(v.getNativePointer());
}
- static native int sqlite3_value_type(@NotNull long ptrToValue);
+ private static native int sqlite3_value_type(@NotNull long ptrToValue);
public static int sqlite3_value_type(@NotNull sqlite3_value v){
return sqlite3_value_type(v.getNativePointer());
@@ -2255,7 +2702,6 @@ public static int sqlite3_value_type(@NotNull sqlite3_value v){
// prepare flags
public static final int SQLITE_PREPARE_PERSISTENT = 1;
- public static final int SQLITE_PREPARE_NORMALIZE = 2;
public static final int SQLITE_PREPARE_NO_VTAB = 4;
// result codes
@@ -2411,9 +2857,11 @@ public static int sqlite3_value_type(@NotNull sqlite3_value v){
public static final int SQLITE_TXN_WRITE = 2;
// udf flags
- public static final int SQLITE_DETERMINISTIC = 0x000000800;
- public static final int SQLITE_DIRECTONLY = 0x000080000;
- public static final int SQLITE_INNOCUOUS = 0x000200000;
+ public static final int SQLITE_DETERMINISTIC = 0x000000800;
+ public static final int SQLITE_DIRECTONLY = 0x000080000;
+ public static final int SQLITE_SUBTYPE = 0x000100000;
+ public static final int SQLITE_INNOCUOUS = 0x000200000;
+ public static final int SQLITE_RESULT_SUBTYPE = 0x001000000;
// virtual tables
public static final int SQLITE_INDEX_SCAN_UNIQUE = 1;
@@ -2442,8 +2890,8 @@ public static int sqlite3_value_type(@NotNull sqlite3_value v){
public static final int SQLITE_FAIL = 3;
public static final int SQLITE_REPLACE = 5;
static {
- // This MUST come after the SQLITE_MAX_... values or else
- // attempting to modify them silently fails.
init();
}
+ /* Must come after static init(). */
+ private static final boolean JNI_SUPPORTS_NIO = sqlite3_jni_supports_nio();
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java b/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java
index 0495702561..7df748e8d8 100644
--- a/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java
+++ b/ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java
@@ -24,8 +24,9 @@ callback interface on behalf of the C library.
propagated. For callback interfaces which support returning error
info to the core, the JNI binding will convert any exceptions to
C-level error information. For callback interfaces which do not
- support, all exceptions will necessarily be suppressed in order to
- retain the C-style no-throw semantics.
+ support returning error information, all exceptions will
+ necessarily be suppressed in order to retain the C-style no-throw
+ semantics and avoid invoking undefined behavior in the C layer.
Callbacks of this style follow a common naming convention:
diff --git a/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java b/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java
index fe61fe5065..ffd7fa94ab 100644
--- a/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java
@@ -21,8 +21,9 @@ public interface CollationNeededCallback extends CallbackProxy {
Has the same semantics as the C-level sqlite3_create_collation()
callback.
-
If it throws, the exception message is passed on to the db and
- the exception is suppressed.
+
Because the C API has no mechanism for reporting errors
+ from this callbacks, any exceptions thrown by this callback
+ are suppressed.
*/
- int call(sqlite3 db, int eTextRep, String collationName);
+ void call(sqlite3 db, int eTextRep, String collationName);
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java
index 24373bdf2b..e1e55c78d2 100644
--- a/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java
@@ -19,7 +19,8 @@
public interface CommitHookCallback extends CallbackProxy {
/**
Works as documented for the C-level sqlite3_commit_hook()
- callback. Must not throw.
+ callback. If it throws, the exception is translated into
+ a db-level error.
*/
int call();
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java b/ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java
similarity index 86%
rename from ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java
rename to ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java
index df753e6513..a5530b49a4 100644
--- a/ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java
@@ -16,10 +16,10 @@
/**
A callback for use with sqlite3_config().
*/
-public interface ConfigSqllogCallback {
+public interface ConfigSqlLogCallback {
/**
Must function as described for a C-level callback for
- {@link CApi#sqlite3_config(ConfigSqllogCallback)}, with the slight signature change.
+ {@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
*/
void call(sqlite3 db, String msg, int msgType );
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java b/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java
index 60b9025386..7bf7529da1 100644
--- a/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java
+++ b/ext/jni/src/org/sqlite/jni/capi/OutputPointer.java
@@ -228,4 +228,26 @@ public static final class ByteArray {
/** Sets the current value. */
public final void set(byte[] v){value = v;}
}
+
+ /**
+ Output pointer for use with native routines which return
+ blobs via java.nio.ByteBuffer.
+
+ See {@link org.sqlite.jni.capi.CApi#sqlite3_jni_supports_nio}
+ */
+ public static final class ByteBuffer {
+ /**
+ This is public for ease of use. Accessors are provided for
+ consistency with the higher-level types.
+ */
+ public java.nio.ByteBuffer value;
+ /** Initializes with the value null. */
+ public ByteBuffer(){this(null);}
+ /** Initializes with the value v. */
+ public ByteBuffer(java.nio.ByteBuffer v){value = v;}
+ /** Returns the current value. */
+ public final java.nio.ByteBuffer get(){return value;}
+ /** Sets the current value. */
+ public final void set(java.nio.ByteBuffer v){value = v;}
+ }
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java b/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
index 1c805a9b16..9f6dd478ce 100644
--- a/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java
@@ -25,7 +25,10 @@ public interface PrepareMultiCallback extends CallbackProxy {
sqlite3_prepare_multi() will _not_ finalize st - it is up
to the call() implementation how st is handled.
- Must return 0 on success or an SQLITE_... code on error.
+ Must return 0 on success or an SQLITE_... code on error. If it
+ throws, sqlite3_prepare_multi() will transform the exception into
+ a db-level error in order to retain the C-style error semantics
+ of the API.
See the {@link Finalize} class for a wrapper which finalizes the
statement after calling a proxy PrepareMultiCallback.
@@ -37,7 +40,7 @@ to the call() implementation how st is handled.
any sqlite3_stmt passed to its callback.
*/
public static final class Finalize implements PrepareMultiCallback {
- private PrepareMultiCallback p;
+ private final PrepareMultiCallback p;
/**
p is the proxy to call() when this.call() is called.
*/
diff --git a/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java
index 99d3fb0351..38f7c5613e 100644
--- a/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java
@@ -19,7 +19,8 @@
public interface PreupdateHookCallback extends CallbackProxy {
/**
Must function as described for the C-level sqlite3_preupdate_hook()
- callback.
+ callback. If it throws, the exception is translated to a
+ db-level error and the exception is suppressed.
*/
void call(sqlite3 db, int op, String dbName, String dbTable,
long iKey1, long iKey2 );
diff --git a/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java
index 5ce17e718a..cf9c4b6e7a 100644
--- a/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java
@@ -18,8 +18,9 @@
*/
public interface RollbackHookCallback extends CallbackProxy {
/**
- Works as documented for the C-level sqlite3_rollback_hook()
- callback.
+ Must function as documented for the C-level sqlite3_rollback_hook()
+ callback. If it throws, the exception is translated into
+ a db-level error.
*/
void call();
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/SQLFunction.java b/ext/jni/src/org/sqlite/jni/capi/SQLFunction.java
index 4806e2fc0c..7ad1381a7a 100644
--- a/ext/jni/src/org/sqlite/jni/capi/SQLFunction.java
+++ b/ext/jni/src/org/sqlite/jni/capi/SQLFunction.java
@@ -33,71 +33,4 @@
*/
public interface SQLFunction {
- /**
- PerContextState assists aggregate and window functions in
- managing their accumulator state across calls to the UDF's
- callbacks.
-
-
T must be of a type which can be legally stored as a value in
- java.util.HashMap.
-
-
If a given aggregate or window function is called multiple times
- in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
- then the clients need some way of knowing which call is which so
- that they can map their state between their various UDF callbacks
- and reset it via xFinal(). This class takes care of such
- mappings.
-
-
This class works by mapping
- sqlite3_context.getAggregateContext() to a single piece of
- state, of a client-defined type (the T part of this class), which
- persists across a "matching set" of the UDF's callbacks.
-
-
This class is a helper providing commonly-needed functionality
- - it is not required for use with aggregate or window functions.
- Client UDFs are free to perform such mappings using custom
- approaches. The provided {@link AggregateFunction} and {@link
- WindowFunction} classes use this.
- */
- public static final class PerContextState {
- private final java.util.Map> map
- = new java.util.HashMap<>();
-
- /**
- Should be called from a UDF's xStep(), xValue(), and xInverse()
- methods, passing it that method's first argument and an initial
- value for the persistent state. If there is currently no
- mapping for the given context within the map, one is created
- using the given initial value, else the existing one is used
- and the 2nd argument is ignored. It returns a ValueHolder
- which can be used to modify that state directly without
- requiring that the client update the underlying map's entry.
-
-
The caller is obligated to eventually call
- takeAggregateState() to clear the mapping.
- */
- public ValueHolder getAggregateState(sqlite3_context cx, T initialValue){
- final Long key = cx.getAggregateContext(true);
- ValueHolder rc = null==key ? null : map.get(key);
- if( null==rc ){
- map.put(key, rc = new ValueHolder<>(initialValue));
- }
- return rc;
- }
-
- /**
- Should be called from a UDF's xFinal() method and passed that
- method's first argument. This function removes the value
- associated with cx.getAggregateContext() from the map and
- returns it, returning null if no other UDF method has been
- called to set up such a mapping. The latter condition will be
- the case if a UDF is used in a statement which has no result
- rows.
- */
- public T takeAggregateState(sqlite3_context cx){
- final ValueHolder h = map.remove(cx.getAggregateContext(false));
- return null==h ? null : h.value;
- }
- }
-
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/SQLTester.java b/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
index 81d6106be7..c68785e2c3 100644
--- a/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
+++ b/ext/jni/src/org/sqlite/jni/capi/SQLTester.java
@@ -851,11 +851,26 @@ class JsonBlockCommand extends TableResultCommand {
//! --new command
class NewDbCommand extends OpenDbCommand {
public NewDbCommand(){ super(true); }
+ public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
+ if(argv.length>1){
+ Util.unlink(argv[1]);
+ }
+ super.process(t, ts, argv);
+ }
+
}
-//! Placeholder dummy/no-op commands
+//! Placeholder dummy/no-op/unimplemented commands
class NoopCommand extends Command {
+ private boolean verbose = false;
+ public NoopCommand(boolean verbose){
+ this.verbose = verbose;
+ }
+ public NoopCommand(){}
public void process(SQLTester t, TestScript ts, String[] argv) throws Exception{
+ if( this.verbose ){
+ t.outln("Skipping unhandled command: "+argv[0]);
+ }
}
}
@@ -1021,6 +1036,7 @@ static Command getCommandByName(String name){
case "db": rv = new DbCommand(); break;
case "glob": rv = new GlobCommand(); break;
case "json": rv = new JsonCommand(); break;
+ case "jsonglob": rv = new NoopCommand(true); break;
case "json-block": rv = new JsonBlockCommand(); break;
case "new": rv = new NewDbCommand(); break;
case "notglob": rv = new NotGlobCommand(); break;
@@ -1030,6 +1046,7 @@ static Command getCommandByName(String name){
case "print": rv = new PrintCommand(); break;
case "result": rv = new ResultCommand(); break;
case "run": rv = new RunCommand(); break;
+ case "stmt-cache": rv = new NoopCommand(); break;
case "tableresult": rv = new TableResultCommand(); break;
case "testcase": rv = new TestCaseCommand(); break;
case "verbosity": rv = new VerbosityCommand(); break;
diff --git a/ext/jni/src/org/sqlite/jni/capi/Tester1.java b/ext/jni/src/org/sqlite/jni/capi/Tester1.java
index 6fb28e65b9..05b1cfeaed 100644
--- a/ext/jni/src/org/sqlite/jni/capi/Tester1.java
+++ b/ext/jni/src/org/sqlite/jni/capi/Tester1.java
@@ -38,6 +38,14 @@
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@interface SingleThreadOnly{}
+/**
+ Annotation for Tester1 tests which must only be run if
+ sqlite3_jni_supports_nio() is true.
+*/
+@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
+@interface RequiresJniNio{}
+
public class Tester1 implements Runnable {
//! True when running in multi-threaded mode.
private static boolean mtMode = false;
@@ -46,7 +54,7 @@ public class Tester1 implements Runnable {
//! True to shuffle the order of the tests.
private static boolean shuffle = false;
//! True to dump the list of to-run tests to stdout.
- private static boolean listRunTests = false;
+ private static int listRunTests = 0;
//! True to squelch all out() and outln() output.
private static boolean quietMode = false;
//! Total number of runTests() calls.
@@ -327,7 +335,7 @@ private void testPrepare123(){
rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)",
- SQLITE_PREPARE_NORMALIZE, outStmt);
+ 0, outStmt);
affirm(0 == rc);
stmt = outStmt.get();
affirm(0 != stmt.getNativePointer());
@@ -382,6 +390,15 @@ private void testBindFetchInt(){
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
affirm( sqlite3_stmt_readonly(stmt) );
affirm( !sqlite3_stmt_busy(stmt) );
+ if( sqlite3_compileoption_used("ENABLE_COLUMN_METADATA") ){
+ /* Unlike in native C code, JNI won't trigger an
+ UnsatisfiedLinkError until these are called (on Linux, at
+ least). */
+ affirm("t".equals(sqlite3_column_table_name(stmt,0)));
+ affirm("main".equals(sqlite3_column_database_name(stmt,0)));
+ affirm("a".equals(sqlite3_column_origin_name(stmt,0)));
+ }
+
int total2 = 0;
while( SQLITE_ROW == sqlite3_step(stmt) ){
affirm( sqlite3_stmt_busy(stmt) );
@@ -477,6 +494,7 @@ private void testBindFetchText(){
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
StringBuilder sbuf = new StringBuilder();
n = 0;
+ final boolean tryNio = sqlite3_jni_supports_nio();
while( SQLITE_ROW == sqlite3_step(stmt) ){
final sqlite3_value sv = sqlite3_value_dup(sqlite3_column_value(stmt,0));
final String txt = sqlite3_column_text16(stmt, 0);
@@ -491,6 +509,15 @@ private void testBindFetchText(){
StandardCharsets.UTF_8)) );
affirm( txt.length() == sqlite3_value_bytes16(sv)/2 );
affirm( txt.equals(sqlite3_value_text16(sv)) );
+ if( tryNio ){
+ java.nio.ByteBuffer bu = sqlite3_value_nio_buffer(sv);
+ byte ba[] = sqlite3_value_blob(sv);
+ affirm( ba.length == bu.capacity() );
+ int i = 0;
+ for( byte b : ba ){
+ affirm( b == bu.get(i++) );
+ }
+ }
sqlite3_value_free(sv);
++n;
}
@@ -548,6 +575,79 @@ private void testBindFetchBlob(){
sqlite3_close_v2(db);
}
+ @RequiresJniNio
+ private void testBindByteBuffer(){
+ /* TODO: these tests need to be much more extensive to check the
+ begin/end range handling. */
+
+ java.nio.ByteBuffer zeroCheck =
+ java.nio.ByteBuffer.allocateDirect(0);
+ affirm( null != zeroCheck );
+ zeroCheck = null;
+ sqlite3 db = createNewDb();
+ execSql(db, "CREATE TABLE t(a)");
+
+ final java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocateDirect(10);
+ buf.put((byte)0x31)/*note that we'll skip this one*/
+ .put((byte)0x32)
+ .put((byte)0x33)
+ .put((byte)0x34)
+ .put((byte)0x35)/*we'll skip this one too*/;
+
+ final int expectTotal = buf.get(1) + buf.get(2) + buf.get(3);
+ sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
+ affirm( SQLITE_ERROR == sqlite3_bind_blob(stmt, 1, buf, -1, 0),
+ "Buffer offset may not be negative." );
+ affirm( 0 == sqlite3_bind_blob(stmt, 1, buf, 1, 3) );
+ affirm( SQLITE_DONE == sqlite3_step(stmt) );
+ sqlite3_finalize(stmt);
+ stmt = prepare(db, "SELECT a FROM t;");
+ int total = 0;
+ affirm( SQLITE_ROW == sqlite3_step(stmt) );
+ byte blob[] = sqlite3_column_blob(stmt, 0);
+ java.nio.ByteBuffer nioBlob =
+ sqlite3_column_nio_buffer(stmt, 0);
+ affirm(3 == blob.length);
+ affirm(blob.length == nioBlob.capacity());
+ affirm(blob.length == nioBlob.limit());
+ int i = 0;
+ for(byte b : blob){
+ affirm( i<=3 );
+ affirm(b == buf.get(1 + i));
+ affirm(b == nioBlob.get(i));
+ ++i;
+ total += b;
+ }
+ affirm( SQLITE_DONE == sqlite3_step(stmt) );
+ sqlite3_finalize(stmt);
+ affirm(total == expectTotal);
+
+ SQLFunction func =
+ new ScalarFunction(){
+ public void xFunc(sqlite3_context cx, sqlite3_value[] args){
+ sqlite3_result_blob(cx, buf, 1, 3);
+ }
+ };
+
+ affirm( 0 == sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func) );
+ stmt = prepare(db, "SELECT myfunc()");
+ affirm( SQLITE_ROW == sqlite3_step(stmt) );
+ blob = sqlite3_column_blob(stmt, 0);
+ affirm(3 == blob.length);
+ i = 0;
+ total = 0;
+ for(byte b : blob){
+ affirm( i<=3 );
+ affirm(b == buf.get(1 + i++));
+ total += b;
+ }
+ affirm( SQLITE_DONE == sqlite3_step(stmt) );
+ sqlite3_finalize(stmt);
+ affirm(total == expectTotal);
+
+ sqlite3_close_v2(db);
+ }
+
private void testSql(){
sqlite3 db = createNewDb();
sqlite3_stmt stmt = prepare(db, "SELECT 1");
@@ -593,9 +693,9 @@ public void xDestroy() {
};
final CollationNeededCallback collLoader = new CollationNeededCallback(){
@Override
- public int call(sqlite3 dbArg, int eTextRep, String collationName){
+ public void call(sqlite3 dbArg, int eTextRep, String collationName){
affirm(dbArg == db/* as opposed to a temporary object*/);
- return sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
+ sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
}
};
int rc = sqlite3_collation_needed(db, collLoader);
@@ -803,13 +903,17 @@ public void xFunc(sqlite3_context cx, sqlite3_value args[]){
affirm( 0==rc );
int n = 0;
if( SQLITE_ROW == sqlite3_step(stmt) ){
+ affirm( testResult.value == sqlite3_column_java_object(stmt, 0) );
+ affirm( testResult.value == sqlite3_column_java_object(stmt, 0, sqlite3.class) );
+ affirm( null == sqlite3_column_java_object(stmt, 0, sqlite3_stmt.class) );
+ affirm( null == sqlite3_column_java_object(stmt,1) );
final sqlite3_value v = sqlite3_column_value(stmt, 0);
affirm( testResult.value == sqlite3_value_java_object(v) );
- affirm( testResult.value == sqlite3_value_java_casted(v, sqlite3.class) );
+ affirm( testResult.value == sqlite3_value_java_object(v, sqlite3.class) );
affirm( testResult.value ==
- sqlite3_value_java_casted(v, testResult.value.getClass()) );
- affirm( testResult.value == sqlite3_value_java_casted(v, Object.class) );
- affirm( null == sqlite3_value_java_casted(v, String.class) );
+ sqlite3_value_java_object(v, testResult.value.getClass()) );
+ affirm( testResult.value == sqlite3_value_java_object(v, Object.class) );
+ affirm( null == sqlite3_value_java_object(v, String.class) );
++n;
}
sqlite3_finalize(stmt);
@@ -824,15 +928,28 @@ private void testUdfAggregate(){
// To confirm that xFinal() is called with no aggregate state
// when the corresponding result set is empty.
new ValueHolder<>(false);
+ final ValueHolder neverEverDoThisInClientCode = new ValueHolder<>(null);
+ final ValueHolder neverEverDoThisInClientCode2 = new ValueHolder<>(null);
SQLFunction func = new AggregateFunction(){
@Override
public void xStep(sqlite3_context cx, sqlite3_value[] args){
+ if( null==neverEverDoThisInClientCode.value ){
+ /* !!!NEVER!!! hold a reference to an sqlite3_value or
+ sqlite3_context object like this in client code! They
+ are ONLY legal for the duration of their single
+ call. We do it here ONLY to test that the defenses
+ against clients doing this are working. */
+ neverEverDoThisInClientCode.value = args;
+ }
final ValueHolder agg = this.getAggregateState(cx, 0);
agg.value += sqlite3_value_int(args[0]);
affirm( agg == this.getAggregateState(cx, 0) );
}
@Override
public void xFinal(sqlite3_context cx){
+ if( null==neverEverDoThisInClientCode2.value ){
+ neverEverDoThisInClientCode2.value = cx;
+ }
final Integer v = this.takeAggregateState(cx);
if(null == v){
xFinalNull.value = true;
@@ -857,6 +974,10 @@ public void xFinal(sqlite3_context cx){
}
affirm( 1==n );
affirm(!xFinalNull.value);
+ affirm( null!=neverEverDoThisInClientCode.value );
+ affirm( null!=neverEverDoThisInClientCode2.value );
+ affirm( 0 xBusyCalled = new ValueHolder<>(0);
- BusyHandlerCallback handler = new BusyHandlerCallback(){
- @Override public int call(int n){
- //outln("busy handler #"+n);
- return n > 2 ? 0 : ++xBusyCalled.value;
- }
- };
- rc = sqlite3_busy_handler(db2, handler);
- affirm(0 == rc);
+ int rc = sqlite3_open(dbName, outDb);
+ ++metrics.dbOpen;
+ affirm( 0 == rc );
+ final sqlite3 db1 = outDb.get();
+ execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
+ rc = sqlite3_open(dbName, outDb);
+ ++metrics.dbOpen;
+ affirm( 0 == rc );
+ affirm( outDb.get() != db1 );
+ final sqlite3 db2 = outDb.get();
+
+ affirm( "main".equals( sqlite3_db_name(db1, 0) ) );
+ rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
+ affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
+ affirm( "foo".equals( sqlite3_db_name(db1, 0) ) );
+ affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) );
+
+ final ValueHolder xBusyCalled = new ValueHolder<>(0);
+ BusyHandlerCallback handler = new BusyHandlerCallback(){
+ @Override public int call(int n){
+ //outln("busy handler #"+n);
+ return n > 2 ? 0 : ++xBusyCalled.value;
+ }
+ };
+ rc = sqlite3_busy_handler(db2, handler);
+ affirm(0 == rc);
- // Force a locked condition...
- execSql(db1, "BEGIN EXCLUSIVE");
- rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
- affirm( SQLITE_BUSY == rc);
- affirm( null == outStmt.get() );
- affirm( 3 == xBusyCalled.value );
- sqlite3_close_v2(db1);
- sqlite3_close_v2(db2);
- try{
- final java.io.File f = new java.io.File(dbName);
- f.delete();
- }catch(Exception e){
- /* ignore */
+ // Force a locked condition...
+ execSql(db1, "BEGIN EXCLUSIVE");
+ rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
+ affirm( SQLITE_BUSY == rc);
+ affirm( null == outStmt.get() );
+ affirm( 3 == xBusyCalled.value );
+ sqlite3_close_v2(db1);
+ sqlite3_close_v2(db2);
+ }finally{
+ try{(new java.io.File(dbName)).delete();}
+ catch(Exception e){/* ignore */}
}
}
@@ -1093,6 +1213,7 @@ private void testProgress(){
private void testCommitHook(){
final sqlite3 db = createNewDb();
+ sqlite3_extended_result_codes(db, true);
final ValueHolder counter = new ValueHolder<>(0);
final ValueHolder hookResult = new ValueHolder<>(0);
final CommitHookCallback theHook = new CommitHookCallback(){
@@ -1135,7 +1256,7 @@ private void testCommitHook(){
affirm( 5 == counter.value );
hookResult.value = SQLITE_ERROR;
int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
- affirm( SQLITE_CONSTRAINT == rc );
+ affirm( SQLITE_CONSTRAINT_COMMITHOOK == rc );
affirm( 6 == counter.value );
sqlite3_close_v2(db);
}
@@ -1354,6 +1475,9 @@ public int call(int op, String s0, String s1, String s2, String s3){
authRc.value = SQLITE_DENY;
int rc = execSql(db, false, "UPDATE t SET a=2");
affirm( SQLITE_AUTH==rc );
+ sqlite3_set_authorizer(db, null);
+ rc = execSql(db, false, "UPDATE t SET a=2");
+ affirm( 0==rc );
// TODO: expand these tests considerably
sqlite3_close(db);
}
@@ -1415,7 +1539,7 @@ private synchronized void testAutoExtension(){
val.value = 0;
final AutoExtensionCallback ax2 = new AutoExtensionCallback(){
- @Override public synchronized int call(sqlite3 db){
+ @Override public int call(sqlite3 db){
++val.value;
return 0;
}
@@ -1626,7 +1750,7 @@ private void testBlobOpen(){
sqlite3_finalize(stmt);
b = sqlite3_blob_open(db, "main", "t", "a",
- sqlite3_last_insert_rowid(db), 1);
+ sqlite3_last_insert_rowid(db), 0);
affirm( null!=b );
rc = sqlite3_blob_reopen(b, 2);
affirm( 0==rc );
@@ -1636,6 +1760,86 @@ private void testBlobOpen(){
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
rc = sqlite3_blob_close(b);
affirm( 0==rc );
+
+ if( !sqlite3_jni_supports_nio() ){
+ outln("WARNING: skipping tests for ByteBuffer-using sqlite3_blob APIs ",
+ "because this platform lacks that support.");
+ sqlite3_close_v2(db);
+ return;
+ }
+ /* Sanity checks for the java.nio.ByteBuffer-taking overloads of
+ sqlite3_blob_read/write(). */
+ execSql(db, "UPDATE t SET a=zeroblob(10)");
+ b = sqlite3_blob_open(db, "main", "t", "a", 1, 1);
+ affirm( null!=b );
+ java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocateDirect(10);
+ for( byte i = 0; i < 10; ++i ){
+ bb.put((int)i, (byte)(48+i & 0xff));
+ }
+ rc = sqlite3_blob_write(b, 1, bb, 1, 10);
+ affirm( rc==SQLITE_ERROR, "b length < (srcOffset + bb length)" );
+ rc = sqlite3_blob_write(b, -1, bb);
+ affirm( rc==SQLITE_ERROR, "Target offset may not be negative" );
+ rc = sqlite3_blob_write(b, 0, bb, -1, -1);
+ affirm( rc==SQLITE_ERROR, "Source offset may not be negative" );
+ rc = sqlite3_blob_write(b, 1, bb, 1, 8);
+ affirm( rc==0 );
+ // b's contents: 0 49 50 51 52 53 54 55 56 0
+ // ascii: 0 '1' '2' '3' '4' '5' '6' '7' '8' 0
+ byte br[] = new byte[10];
+ java.nio.ByteBuffer bbr =
+ java.nio.ByteBuffer.allocateDirect(bb.limit());
+ rc = sqlite3_blob_read( b, br, 0 );
+ affirm( rc==0 );
+ rc = sqlite3_blob_read( b, bbr );
+ affirm( rc==0 );
+ java.nio.ByteBuffer bbr2 = sqlite3_blob_read_nio_buffer(b, 0, 12);
+ affirm( null==bbr2, "Read size is too big");
+ bbr2 = sqlite3_blob_read_nio_buffer(b, -1, 3);
+ affirm( null==bbr2, "Source offset is negative");
+ bbr2 = sqlite3_blob_read_nio_buffer(b, 5, 6);
+ affirm( null==bbr2, "Read pos+size is too big");
+ bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 7);
+ affirm( null==bbr2, "Read pos+size is too big");
+ bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 6);
+ affirm( null!=bbr2 );
+ java.nio.ByteBuffer bbr3 =
+ java.nio.ByteBuffer.allocateDirect(2 * bb.limit());
+ java.nio.ByteBuffer bbr4 =
+ java.nio.ByteBuffer.allocateDirect(5);
+ rc = sqlite3_blob_read( b, bbr3 );
+ affirm( rc==0 );
+ rc = sqlite3_blob_read( b, bbr4 );
+ affirm( rc==0 );
+ affirm( sqlite3_blob_bytes(b)==bbr3.limit() );
+ affirm( 5==bbr4.limit() );
+ sqlite3_blob_close(b);
+ affirm( 0==br[0] );
+ affirm( 0==br[9] );
+ affirm( 0==bbr.get(0) );
+ affirm( 0==bbr.get(9) );
+ affirm( bbr2.limit() == 6 );
+ affirm( 0==bbr3.get(0) );
+ {
+ Exception ex = null;
+ try{ bbr3.get(11); }
+ catch(Exception e){ex = e;}
+ affirm( ex instanceof IndexOutOfBoundsException,
+ "bbr3.limit() was reset by read()" );
+ ex = null;
+ }
+ affirm( 0==bbr4.get(0) );
+ for( int i = 1; i < 9; ++i ){
+ affirm( br[i] == 48 + i );
+ affirm( br[i] == bbr.get(i) );
+ affirm( br[i] == bbr3.get(i) );
+ if( i>3 ){
+ affirm( br[i] == bbr2.get(i-4) );
+ }
+ if( i < bbr4.limit() ){
+ affirm( br[i] == bbr4.get(i) );
+ }
+ }
sqlite3_close_v2(db);
}
@@ -1648,9 +1852,13 @@ private void testPrepareMulti(){
};
final List liStmt = new ArrayList();
final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
+ final ValueHolder toss = new ValueHolder<>(null);
PrepareMultiCallback m = new PrepareMultiCallback() {
@Override public int call(sqlite3_stmt st){
liStmt.add(st);
+ if( null!=toss.value ){
+ throw new RuntimeException(toss.value);
+ }
return proxy.call(st);
}
};
@@ -1660,6 +1868,10 @@ private void testPrepareMulti(){
for( sqlite3_stmt st : liStmt ){
sqlite3_finalize(st);
}
+ toss.value = "This is an exception.";
+ rc = sqlite3_prepare_multi(db, "SELECT 1", m);
+ affirm( SQLITE_ERROR==rc );
+ affirm( sqlite3_errmsg(db).indexOf(toss.value)>0 );
sqlite3_close_v2(db);
}
@@ -1698,7 +1910,7 @@ private void runTests(boolean fromThread) throws Exception {
mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
java.util.Collections.shuffle(mlist);
}
- if( listRunTests ){
+ if( (!fromThread && listRunTests>0) || listRunTests>1 ){
synchronized(this.getClass()){
if( !fromThread ){
out("Initial test"," list: ");
@@ -1760,8 +1972,11 @@ public void run() {
-naps: sleep small random intervals between tests in order to add
some chaos for cross-thread contention.
+
-list-tests: outputs the list of tests being run, minus some
- which are hard-coded. This is noisy in multi-threaded mode.
+ which are hard-coded. In multi-threaded mode, use this twice to
+ to emit the list run by each thread (which may differ from the initial
+ list, in particular if -shuffle is used).
-fail: forces an exception to be thrown during the test run. Use
with -shuffle to make its appearance unpredictable.
@@ -1790,7 +2005,7 @@ public static void main(String[] args) throws Exception {
}else if(arg.equals("shuffle")){
shuffle = true;
}else if(arg.equals("list-tests")){
- listRunTests = true;
+ ++listRunTests;
}else if(arg.equals("fail")){
forceFail = true;
}else if(arg.equals("sqllog")){
@@ -1809,7 +2024,7 @@ public static void main(String[] args) throws Exception {
if( sqlLog ){
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
- final ConfigSqllogCallback log = new ConfigSqllogCallback() {
+ final ConfigSqlLogCallback log = new ConfigSqlLogCallback() {
@Override public void call(sqlite3 db, String msg, int op){
switch(op){
case 0: outln("Opening db: ",db); break;
@@ -1820,7 +2035,7 @@ public static void main(String[] args) throws Exception {
};
int rc = sqlite3_config( log );
affirm( 0==rc );
- rc = sqlite3_config( (ConfigSqllogCallback)null );
+ rc = sqlite3_config( (ConfigSqlLogCallback)null );
affirm( 0==rc );
rc = sqlite3_config( log );
affirm( 0==rc );
@@ -1858,18 +2073,20 @@ public static void main(String[] args) throws Exception {
if( forceFail ){
testMethods.add(m);
}
+ }else if( m.isAnnotationPresent( RequiresJniNio.class )
+ && !sqlite3_jni_supports_nio() ){
+ outln("Skipping test for lack of JNI java.nio.ByteBuffer support: ",
+ name,"()\n");
+ ++nSkipped;
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
- if( 0==nSkipped++ ){
- out("Skipping tests in multi-thread mode:");
- }
- out(" "+name+"()");
+ out("Skipping test in multi-thread mode: ",name,"()\n");
+ ++nSkipped;
}else if( name.startsWith("test") ){
testMethods.add(m);
}
}
}
- if( nSkipped>0 ) out("\n");
}
final long timeStart = System.currentTimeMillis();
@@ -1901,6 +2118,7 @@ public static void main(String[] args) throws Exception {
sqlite3_libversion_number(),"\n",
sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n",
"SQLITE_THREADSAFE=",sqlite3_threadsafe());
+ outln("JVM NIO support? ",sqlite3_jni_supports_nio() ? "YES" : "NO");
final boolean showLoopCount = (nRepeat>1 && nThread>1);
if( showLoopCount ){
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
diff --git a/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java b/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java
index 33d72a5dd2..e3d491f67e 100644
--- a/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java
+++ b/ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java
@@ -19,7 +19,8 @@
public interface UpdateHookCallback extends CallbackProxy {
/**
Must function as described for the C-level sqlite3_update_hook()
- callback.
+ callback. If it throws, the exception is translated into
+ a db-level error.
*/
void call(int opId, String dbName, String tableName, long rowId);
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java b/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java
index b3f03ac867..0a469fea9a 100644
--- a/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java
+++ b/ext/jni/src/org/sqlite/jni/capi/ValueHolder.java
@@ -9,14 +9,16 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains a set of tests for the sqlite3 JNI bindings.
+** This file contains the ValueHolder utility class for the sqlite3
+** JNI bindings.
*/
package org.sqlite.jni.capi;
/**
A helper class which simply holds a single value. Its primary use
is for communicating values out of anonymous classes, as doing so
- requires a "final" reference.
+ requires a "final" reference, as well as communicating aggregate
+ SQL function state across calls to such functions.
*/
public class ValueHolder {
public T value;
diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3.java
index 901317f0ef..cc6f2e6e8d 100644
--- a/ext/jni/src/org/sqlite/jni/capi/sqlite3.java
+++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3.java
@@ -38,6 +38,6 @@ public String toString(){
}
@Override public void close(){
- CApi.sqlite3_close_v2(this.clearNativePointer());
+ CApi.sqlite3_close_v2(this);
}
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java
index 1b96c18b06..bdc0200af4 100644
--- a/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java
+++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java
@@ -25,7 +25,6 @@ public final class sqlite3_blob extends NativePointerHolder
private sqlite3_blob(){}
@Override public void close(){
- CApi.sqlite3_blob_close(this.clearNativePointer());
+ CApi.sqlite3_blob_close(this);
}
-
}
diff --git a/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java b/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java
index 3b8b71f8a5..564891c727 100644
--- a/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java
+++ b/ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java
@@ -25,6 +25,6 @@ public final class sqlite3_stmt extends NativePointerHolder
private sqlite3_stmt(){}
@Override public void close(){
- CApi.sqlite3_finalize(this.clearNativePointer());
+ CApi.sqlite3_finalize(this);
}
}
diff --git a/ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java b/ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java
index c4264c5417..095e649caf 100644
--- a/ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java
+++ b/ext/jni/src/org/sqlite/jni/fts5/TesterFts5.java
@@ -625,10 +625,20 @@ private static void test2(){
"SELECT fts5_columntext(ft, 1) FROM ft('x') ORDER BY rowid",
"[x, x, x y z, x z, x y z, x]"
);
- do_execsql_test(db,
- "SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
- "[null, null, null, null, null, null]"
- );
+ boolean threw = false;
+ try{
+ /* columntext() used to return NULLs when given an out-of bounds column
+ but now results in a range error. */
+ do_execsql_test(db,
+ "SELECT fts5_columntext(ft, 2) FROM ft('x') ORDER BY rowid",
+ "[null, null, null, null, null, null]"
+ );
+ }catch(Exception e){
+ threw = true;
+ affirm( e.getMessage().matches(".*column index out of range") );
+ }
+ affirm( threw );
+ threw = false;
/* Test fts5_columntotalsize() */
do_execsql_test(db,
diff --git a/ext/jni/src/org/sqlite/jni/test-script-interpreter.md b/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
index a51d64d107..939f77e1be 100644
--- a/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
+++ b/ext/jni/src/org/sqlite/jni/test-script-interpreter.md
@@ -4,7 +4,7 @@
The purpose of the Test Script Interpreter is to read and interpret
script files that contain SQL commands and desired results. The
-interpreter will check results and report an discrepencies found.
+interpreter will check results and report any discrepencies found.
The test script files are ASCII text files. The filename always ends with
".test". Each script is evaluated independently; context does not carry
@@ -87,6 +87,7 @@ Each command looks like an SQL comment. The command begins at the left
margin (no leading space) and starts with exactly 2 minus signs ("-").
The command name consists of lowercase letters and maybe a "-" or two.
Some commands have arguments.
+
The arguments are separated from the command name by one or more spaces.
Commands have access to the input buffer and might reset the input buffer.
@@ -159,9 +160,9 @@ the result buffer. This distinction does not matter for the --result
command itself, but it is important for related commands like --glob
and --notglob. Sometimes test cases will contains a bunch of SQL
followed by multiple --glob and/or --notglob statements. All of the
-globs should be evaluted agains the result buffer correct, but the SQL
-should only be run once. This is accomplished by resetting the input
-buffer but not the result buffer.
+globs should be evaluated agains the result buffer, but the SQL should
+only be run once. This is accomplished by resetting the input buffer
+but not the result buffer.
### The --glob command
@@ -187,7 +188,7 @@ The TEST-GLOB pattern is slightly different for a standard GLOB:
### The --notglob command
The --notglob command works just like --glob except that it reports an
-error if the GLOB does match, rather than if the GLOB does not matches.
+error if the GLOB does match, rather than if the GLOB does not match.
### The --oom command
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java
index 173d775e62..fc63b53542 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java
@@ -12,10 +12,6 @@
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
-import org.sqlite.jni.capi.CApi;
-import org.sqlite.jni.annotation.*;
-import org.sqlite.jni.capi.sqlite3_context;
-import org.sqlite.jni.capi.sqlite3_value;
/**
EXPERIMENTAL/INCOMPLETE/UNTESTED
@@ -51,9 +47,75 @@ arguments for xFinal() but will contain the context object needed
*/
public void xDestroy() {}
+ /**
+ PerContextState assists aggregate and window functions in
+ managing their accumulator state across calls to the UDF's
+ callbacks.
+
+
T must be of a type which can be legally stored as a value in
+ java.util.HashMap.
+
+
If a given aggregate or window function is called multiple times
+ in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
+ then the clients need some way of knowing which call is which so
+ that they can map their state between their various UDF callbacks
+ and reset it via xFinal(). This class takes care of such
+ mappings.
+
+
This class works by mapping
+ sqlite3_context.getAggregateContext() to a single piece of
+ state, of a client-defined type (the T part of this class), which
+ persists across a "matching set" of the UDF's callbacks.
+
+
This class is a helper providing commonly-needed functionality
+ - it is not required for use with aggregate or window functions.
+ Client UDFs are free to perform such mappings using custom
+ approaches. The provided {@link AggregateFunction} and {@link
+ WindowFunction} classes use this.
+ */
+ public static final class PerContextState {
+ private final java.util.Map> map
+ = new java.util.HashMap<>();
+
+ /**
+ Should be called from a UDF's xStep(), xValue(), and xInverse()
+ methods, passing it that method's first argument and an initial
+ value for the persistent state. If there is currently no
+ mapping for the given context within the map, one is created
+ using the given initial value, else the existing one is used
+ and the 2nd argument is ignored. It returns a ValueHolder
+ which can be used to modify that state directly without
+ requiring that the client update the underlying map's entry.
+
+
The caller is obligated to eventually call
+ takeAggregateState() to clear the mapping.
+ */
+ public ValueHolder getAggregateState(SqlFunction.Arguments args, T initialValue){
+ final Long key = args.getContext().getAggregateContext(true);
+ ValueHolder rc = null==key ? null : map.get(key);
+ if( null==rc ){
+ map.put(key, rc = new ValueHolder<>(initialValue));
+ }
+ return rc;
+ }
+
+ /**
+ Should be called from a UDF's xFinal() method and passed that
+ method's first argument. This function removes the value
+ associated with with the arguments' aggregate context from the
+ map and returns it, returning null if no other UDF method has
+ been called to set up such a mapping. The latter condition will
+ be the case if a UDF is used in a statement which has no result
+ rows.
+ */
+ public T takeAggregateState(SqlFunction.Arguments args){
+ final ValueHolder h = map.remove(args.getContext().getAggregateContext(false));
+ return null==h ? null : h.value;
+ }
+ }
+
/** Per-invocation state for the UDF. */
- private final SqlFunction.PerContextState map =
- new SqlFunction.PerContextState<>();
+ private final PerContextState map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
index d6acda5aa5..dcfc2ebebd 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java
@@ -22,6 +22,14 @@
*/
public interface SqlFunction {
+ public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC;
+ public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS;
+ public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY;
+ public static final int SUBTYPE = CApi.SQLITE_SUBTYPE;
+ public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE;
+ public static final int UTF8 = CApi.SQLITE_UTF8;
+ public static final int UTF16 = CApi.SQLITE_UTF16;
+
/**
The Arguments type is an abstraction on top of the lower-level
UDF function argument types. It provides _most_ of the functionality
@@ -45,48 +53,10 @@ public final static class Arguments implements Iterable T getObjectCasted(Class type){ return a.getObjectCasted(ndx, type); }
- public int getType(){return a.getType(ndx);}
- public Object getAuxData(){return a.getAuxData(ndx);}
- public void setAuxData(Object o){a.setAuxData(ndx, o);}
- }
-
- @Override
- public java.util.Iterator iterator(){
- final Arg[] proxies = new Arg[args.length];
- for( int i = 0; i < args.length; ++i ){
- proxies[i] = new Arg(this, i);
- }
- return java.util.Arrays.stream(proxies).iterator();
- }
-
/**
Returns the sqlite3_value at the given argument index or throws
an IllegalArgumentException exception if ndx is out of range.
@@ -100,29 +70,40 @@ private sqlite3_value valueAt(int ndx){
return args[ndx];
}
+ //! Returns the underlying sqlite3_context for these arguments.
sqlite3_context getContext(){return cx;}
+ /**
+ Returns the Sqlite (db) object associated with this UDF call,
+ or null if the UDF is somehow called without such an object or
+ the db has been closed in an untimely manner (e.g. closed by a
+ UDF call).
+ */
+ public Sqlite getDb(){
+ return Sqlite.fromNative( CApi.sqlite3_context_db_handle(cx) );
+ }
+
public int getArgCount(){ return args.length; }
- public int getInt(int arg){return CApi.sqlite3_value_int(valueAt(arg));}
- public long getInt64(int arg){return CApi.sqlite3_value_int64(valueAt(arg));}
- public double getDouble(int arg){return CApi.sqlite3_value_double(valueAt(arg));}
- public byte[] getBlob(int arg){return CApi.sqlite3_value_blob(valueAt(arg));}
- public byte[] getText(int arg){return CApi.sqlite3_value_text(valueAt(arg));}
- public String getText16(int arg){return CApi.sqlite3_value_text16(valueAt(arg));}
- public int getBytes(int arg){return CApi.sqlite3_value_bytes(valueAt(arg));}
- public int getBytes16(int arg){return CApi.sqlite3_value_bytes16(valueAt(arg));}
- public Object getObject(int arg){return CApi.sqlite3_value_java_object(valueAt(arg));}
- public T getObjectCasted(int arg, Class type){
- return CApi.sqlite3_value_java_casted(valueAt(arg), type);
+ public int getInt(int argNdx){return CApi.sqlite3_value_int(valueAt(argNdx));}
+ public long getInt64(int argNdx){return CApi.sqlite3_value_int64(valueAt(argNdx));}
+ public double getDouble(int argNdx){return CApi.sqlite3_value_double(valueAt(argNdx));}
+ public byte[] getBlob(int argNdx){return CApi.sqlite3_value_blob(valueAt(argNdx));}
+ public byte[] getText(int argNdx){return CApi.sqlite3_value_text(valueAt(argNdx));}
+ public String getText16(int argNdx){return CApi.sqlite3_value_text16(valueAt(argNdx));}
+ public int getBytes(int argNdx){return CApi.sqlite3_value_bytes(valueAt(argNdx));}
+ public int getBytes16(int argNdx){return CApi.sqlite3_value_bytes16(valueAt(argNdx));}
+ public Object getObject(int argNdx){return CApi.sqlite3_value_java_object(valueAt(argNdx));}
+ public T getObject(int argNdx, Class type){
+ return CApi.sqlite3_value_java_object(valueAt(argNdx), type);
}
- public int getType(int arg){return CApi.sqlite3_value_type(valueAt(arg));}
- public int getSubtype(int arg){return CApi.sqlite3_value_subtype(valueAt(arg));}
- public int getNumericType(int arg){return CApi.sqlite3_value_numeric_type(valueAt(arg));}
- public int getNoChange(int arg){return CApi.sqlite3_value_nochange(valueAt(arg));}
- public boolean getFromBind(int arg){return CApi.sqlite3_value_frombind(valueAt(arg));}
- public int getEncoding(int arg){return CApi.sqlite3_value_encoding(valueAt(arg));}
+ public int getType(int argNdx){return CApi.sqlite3_value_type(valueAt(argNdx));}
+ public int getSubtype(int argNdx){return CApi.sqlite3_value_subtype(valueAt(argNdx));}
+ public int getNumericType(int argNdx){return CApi.sqlite3_value_numeric_type(valueAt(argNdx));}
+ public int getNoChange(int argNdx){return CApi.sqlite3_value_nochange(valueAt(argNdx));}
+ public boolean getFromBind(int argNdx){return CApi.sqlite3_value_frombind(valueAt(argNdx));}
+ public int getEncoding(int argNdx){return CApi.sqlite3_value_encoding(valueAt(argNdx));}
public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); }
public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); }
@@ -133,7 +114,12 @@ public T getObjectCasted(int arg, Class type){
public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
public void resultNull(){CApi.sqlite3_result_null(cx);}
+ /**
+ Analog to sqlite3_result_value(), using the Value object at the
+ given argument index.
+ */
public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
+ public void resultSubtype(int subtype){CApi.sqlite3_result_subtype(cx, subtype);}
public void resultZeroBlob(long n){
// Throw on error? If n is too big,
// sqlite3_result_error_toobig() is automatically called.
@@ -146,88 +132,75 @@ public void resultZeroBlob(long n){
public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}
- public void setAuxData(int arg, Object o){
+ /**
+ Callbacks should invoke this on OOM errors, instead of throwing
+ OutOfMemoryError, because the latter cannot be propagated
+ through the C API.
+ */
+ public void resultNoMem(){CApi.sqlite3_result_error_nomem(cx);}
+
+ /**
+ Analog to sqlite3_set_auxdata() but throws if argNdx is out of
+ range.
+ */
+ public void setAuxData(int argNdx, Object o){
/* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html
The value of the N parameter to these interfaces should be
non-negative. Future enhancements may make use of negative N
values to define new kinds of function caching behavior.
*/
- valueAt(arg);
- CApi.sqlite3_set_auxdata(cx, arg, o);
+ valueAt(argNdx);
+ CApi.sqlite3_set_auxdata(cx, argNdx, o);
}
- public Object getAuxData(int arg){
- valueAt(arg);
- return CApi.sqlite3_get_auxdata(cx, arg);
+ /**
+ Analog to sqlite3_get_auxdata() but throws if argNdx is out of
+ range.
+ */
+ public Object getAuxData(int argNdx){
+ valueAt(argNdx);
+ return CApi.sqlite3_get_auxdata(cx, argNdx);
}
- }
-
- /**
- PerContextState assists aggregate and window functions in
- managing their accumulator state across calls to the UDF's
- callbacks.
-
-
T must be of a type which can be legally stored as a value in
- java.util.HashMap.
-
-
If a given aggregate or window function is called multiple times
- in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
- then the clients need some way of knowing which call is which so
- that they can map their state between their various UDF callbacks
- and reset it via xFinal(). This class takes care of such
- mappings.
-
-
This class works by mapping
- sqlite3_context.getAggregateContext() to a single piece of
- state, of a client-defined type (the T part of this class), which
- persists across a "matching set" of the UDF's callbacks.
-
-
This class is a helper providing commonly-needed functionality
- - it is not required for use with aggregate or window functions.
- Client UDFs are free to perform such mappings using custom
- approaches. The provided {@link AggregateFunction} and {@link
- WindowFunction} classes use this.
- */
- public static final class PerContextState {
- private final java.util.Map> map
- = new java.util.HashMap<>();
/**
- Should be called from a UDF's xStep(), xValue(), and xInverse()
- methods, passing it that method's first argument and an initial
- value for the persistent state. If there is currently no
- mapping for the given context within the map, one is created
- using the given initial value, else the existing one is used
- and the 2nd argument is ignored. It returns a ValueHolder
- which can be used to modify that state directly without
- requiring that the client update the underlying map's entry.
-
-
The caller is obligated to eventually call
- takeAggregateState() to clear the mapping.
+ Represents a single SqlFunction argument. Primarily intended
+ for use with the Arguments class's Iterable interface.
*/
- public ValueHolder getAggregateState(SqlFunction.Arguments args, T initialValue){
- final Long key = args.getContext().getAggregateContext(true);
- ValueHolder rc = null==key ? null : map.get(key);
- if( null==rc ){
- map.put(key, rc = new ValueHolder<>(initialValue));
+ public final static class Arg {
+ private final Arguments a;
+ private final int ndx;
+ /* Only for use by the Arguments class. */
+ private Arg(Arguments a, int ndx){
+ this.a = a;
+ this.ndx = ndx;
}
- return rc;
+ /** Returns this argument's index in its parent argument list. */
+ public int getIndex(){return ndx;}
+ public int getInt(){return a.getInt(ndx);}
+ public long getInt64(){return a.getInt64(ndx);}
+ public double getDouble(){return a.getDouble(ndx);}
+ public byte[] getBlob(){return a.getBlob(ndx);}
+ public byte[] getText(){return a.getText(ndx);}
+ public String getText16(){return a.getText16(ndx);}
+ public int getBytes(){return a.getBytes(ndx);}
+ public int getBytes16(){return a.getBytes16(ndx);}
+ public Object getObject(){return a.getObject(ndx);}
+ public T getObject(Class type){ return a.getObject(ndx, type); }
+ public int getType(){return a.getType(ndx);}
+ public Object getAuxData(){return a.getAuxData(ndx);}
+ public void setAuxData(Object o){a.setAuxData(ndx, o);}
}
- /**
- Should be called from a UDF's xFinal() method and passed that
- method's first argument. This function removes the value
- associated with with the arguments' aggregate context from the
- map and returns it, returning null if no other UDF method has
- been called to set up such a mapping. The latter condition will
- be the case if a UDF is used in a statement which has no result
- rows.
- */
- public T takeAggregateState(SqlFunction.Arguments args){
- final ValueHolder h = map.remove(args.getContext().getAggregateContext(false));
- return null==h ? null : h.value;
+ @Override
+ public java.util.Iterator iterator(){
+ final Arg[] proxies = new Arg[args.length];
+ for( int i = 0; i < args.length; ++i ){
+ proxies[i] = new Arg(this, i);
+ }
+ return java.util.Arrays.stream(proxies).iterator();
}
+
}
/**
@@ -235,7 +208,7 @@ public T takeAggregateState(SqlFunction.Arguments args){
for use with the org.sqlite.jni.capi.ScalarFunction interface.
*/
static final class ScalarAdapter extends org.sqlite.jni.capi.ScalarFunction {
- final ScalarFunction impl;
+ private final ScalarFunction impl;
ScalarAdapter(ScalarFunction impl){
this.impl = impl;
}
@@ -261,8 +234,9 @@ public void xDestroy(){
Internal-use adapter for wrapping this package's AggregateFunction
for use with the org.sqlite.jni.capi.AggregateFunction interface.
*/
- static final class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
- final AggregateFunction impl;
+ static /*cannot be final without duplicating the whole body in WindowAdapter*/
+ class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
+ private final AggregateFunction impl;
AggregateAdapter(AggregateFunction impl){
this.impl = impl;
}
@@ -282,8 +256,9 @@ public void xStep(sqlite3_context cx, sqlite3_value[] args){
}
/**
- As for the xFinal() argument of the C API's sqlite3_create_function().
- If the proxied function throws, it is translated into a sqlite3_result_error().
+ As for the xFinal() argument of the C API's
+ sqlite3_create_function(). If the proxied function throws, it
+ is translated into a sqlite3_result_error().
*/
public void xFinal(sqlite3_context cx){
try{
@@ -298,4 +273,46 @@ public void xDestroy(){
}
}
+ /**
+ Internal-use adapter for wrapping this package's WindowFunction
+ for use with the org.sqlite.jni.capi.WindowFunction interface.
+ */
+ static final class WindowAdapter extends AggregateAdapter {
+ private final WindowFunction impl;
+ WindowAdapter(WindowFunction impl){
+ super(impl);
+ this.impl = impl;
+ }
+
+ /**
+ Proxies this.impl.xInverse(), adapting the call arguments to that
+ function's signature. If the proxied function throws, it is
+ translated to sqlite_result_error() with the exception's
+ message.
+ */
+ public void xInverse(sqlite3_context cx, sqlite3_value[] args){
+ try{
+ impl.xInverse( new SqlFunction.Arguments(cx, args) );
+ }catch(Exception e){
+ CApi.sqlite3_result_error(cx, e);
+ }
+ }
+
+ /**
+ As for the xValue() argument of the C API's sqlite3_create_window_function().
+ If the proxied function throws, it is translated into a sqlite3_result_error().
+ */
+ public void xValue(sqlite3_context cx){
+ try{
+ impl.xValue( new SqlFunction.Arguments(cx, null) );
+ }catch(Exception e){
+ CApi.sqlite3_result_error(cx, e);
+ }
+ }
+
+ public void xDestroy(){
+ impl.xDestroy();
+ }
+ }
+
}
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
index bcf97b2394..de131e8542 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java
@@ -13,11 +13,13 @@
*/
package org.sqlite.jni.wrapper1;
import java.nio.charset.StandardCharsets;
-import static org.sqlite.jni.capi.CApi.*;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;
import org.sqlite.jni.capi.sqlite3_stmt;
+import org.sqlite.jni.capi.sqlite3_backup;
+import org.sqlite.jni.capi.sqlite3_blob;
import org.sqlite.jni.capi.OutputPointer;
+import java.nio.ByteBuffer;
/**
This class represents a database connection, analog to the C-side
@@ -28,12 +30,296 @@
*/
public final class Sqlite implements AutoCloseable {
private sqlite3 db;
+ private static final boolean JNI_SUPPORTS_NIO =
+ CApi.sqlite3_jni_supports_nio();
+
+ // Result codes
+ public static final int OK = CApi.SQLITE_OK;
+ public static final int ERROR = CApi.SQLITE_ERROR;
+ public static final int INTERNAL = CApi.SQLITE_INTERNAL;
+ public static final int PERM = CApi.SQLITE_PERM;
+ public static final int ABORT = CApi.SQLITE_ABORT;
+ public static final int BUSY = CApi.SQLITE_BUSY;
+ public static final int LOCKED = CApi.SQLITE_LOCKED;
+ public static final int NOMEM = CApi.SQLITE_NOMEM;
+ public static final int READONLY = CApi.SQLITE_READONLY;
+ public static final int INTERRUPT = CApi.SQLITE_INTERRUPT;
+ public static final int IOERR = CApi.SQLITE_IOERR;
+ public static final int CORRUPT = CApi.SQLITE_CORRUPT;
+ public static final int NOTFOUND = CApi.SQLITE_NOTFOUND;
+ public static final int FULL = CApi.SQLITE_FULL;
+ public static final int CANTOPEN = CApi.SQLITE_CANTOPEN;
+ public static final int PROTOCOL = CApi.SQLITE_PROTOCOL;
+ public static final int EMPTY = CApi.SQLITE_EMPTY;
+ public static final int SCHEMA = CApi.SQLITE_SCHEMA;
+ public static final int TOOBIG = CApi.SQLITE_TOOBIG;
+ public static final int CONSTRAINT = CApi. SQLITE_CONSTRAINT;
+ public static final int MISMATCH = CApi.SQLITE_MISMATCH;
+ public static final int MISUSE = CApi.SQLITE_MISUSE;
+ public static final int NOLFS = CApi.SQLITE_NOLFS;
+ public static final int AUTH = CApi.SQLITE_AUTH;
+ public static final int FORMAT = CApi.SQLITE_FORMAT;
+ public static final int RANGE = CApi.SQLITE_RANGE;
+ public static final int NOTADB = CApi.SQLITE_NOTADB;
+ public static final int NOTICE = CApi.SQLITE_NOTICE;
+ public static final int WARNING = CApi.SQLITE_WARNING;
+ public static final int ROW = CApi.SQLITE_ROW;
+ public static final int DONE = CApi.SQLITE_DONE;
+ public static final int ERROR_MISSING_COLLSEQ = CApi.SQLITE_ERROR_MISSING_COLLSEQ;
+ public static final int ERROR_RETRY = CApi.SQLITE_ERROR_RETRY;
+ public static final int ERROR_SNAPSHOT = CApi.SQLITE_ERROR_SNAPSHOT;
+ public static final int IOERR_READ = CApi.SQLITE_IOERR_READ;
+ public static final int IOERR_SHORT_READ = CApi.SQLITE_IOERR_SHORT_READ;
+ public static final int IOERR_WRITE = CApi.SQLITE_IOERR_WRITE;
+ public static final int IOERR_FSYNC = CApi.SQLITE_IOERR_FSYNC;
+ public static final int IOERR_DIR_FSYNC = CApi.SQLITE_IOERR_DIR_FSYNC;
+ public static final int IOERR_TRUNCATE = CApi.SQLITE_IOERR_TRUNCATE;
+ public static final int IOERR_FSTAT = CApi.SQLITE_IOERR_FSTAT;
+ public static final int IOERR_UNLOCK = CApi.SQLITE_IOERR_UNLOCK;
+ public static final int IOERR_RDLOCK = CApi.SQLITE_IOERR_RDLOCK;
+ public static final int IOERR_DELETE = CApi.SQLITE_IOERR_DELETE;
+ public static final int IOERR_BLOCKED = CApi.SQLITE_IOERR_BLOCKED;
+ public static final int IOERR_NOMEM = CApi.SQLITE_IOERR_NOMEM;
+ public static final int IOERR_ACCESS = CApi.SQLITE_IOERR_ACCESS;
+ public static final int IOERR_CHECKRESERVEDLOCK = CApi.SQLITE_IOERR_CHECKRESERVEDLOCK;
+ public static final int IOERR_LOCK = CApi.SQLITE_IOERR_LOCK;
+ public static final int IOERR_CLOSE = CApi.SQLITE_IOERR_CLOSE;
+ public static final int IOERR_DIR_CLOSE = CApi.SQLITE_IOERR_DIR_CLOSE;
+ public static final int IOERR_SHMOPEN = CApi.SQLITE_IOERR_SHMOPEN;
+ public static final int IOERR_SHMSIZE = CApi.SQLITE_IOERR_SHMSIZE;
+ public static final int IOERR_SHMLOCK = CApi.SQLITE_IOERR_SHMLOCK;
+ public static final int IOERR_SHMMAP = CApi.SQLITE_IOERR_SHMMAP;
+ public static final int IOERR_SEEK = CApi.SQLITE_IOERR_SEEK;
+ public static final int IOERR_DELETE_NOENT = CApi.SQLITE_IOERR_DELETE_NOENT;
+ public static final int IOERR_MMAP = CApi.SQLITE_IOERR_MMAP;
+ public static final int IOERR_GETTEMPPATH = CApi.SQLITE_IOERR_GETTEMPPATH;
+ public static final int IOERR_CONVPATH = CApi.SQLITE_IOERR_CONVPATH;
+ public static final int IOERR_VNODE = CApi.SQLITE_IOERR_VNODE;
+ public static final int IOERR_AUTH = CApi.SQLITE_IOERR_AUTH;
+ public static final int IOERR_BEGIN_ATOMIC = CApi.SQLITE_IOERR_BEGIN_ATOMIC;
+ public static final int IOERR_COMMIT_ATOMIC = CApi.SQLITE_IOERR_COMMIT_ATOMIC;
+ public static final int IOERR_ROLLBACK_ATOMIC = CApi.SQLITE_IOERR_ROLLBACK_ATOMIC;
+ public static final int IOERR_DATA = CApi.SQLITE_IOERR_DATA;
+ public static final int IOERR_CORRUPTFS = CApi.SQLITE_IOERR_CORRUPTFS;
+ public static final int LOCKED_SHAREDCACHE = CApi.SQLITE_LOCKED_SHAREDCACHE;
+ public static final int LOCKED_VTAB = CApi.SQLITE_LOCKED_VTAB;
+ public static final int BUSY_RECOVERY = CApi.SQLITE_BUSY_RECOVERY;
+ public static final int BUSY_SNAPSHOT = CApi.SQLITE_BUSY_SNAPSHOT;
+ public static final int BUSY_TIMEOUT = CApi.SQLITE_BUSY_TIMEOUT;
+ public static final int CANTOPEN_NOTEMPDIR = CApi.SQLITE_CANTOPEN_NOTEMPDIR;
+ public static final int CANTOPEN_ISDIR = CApi.SQLITE_CANTOPEN_ISDIR;
+ public static final int CANTOPEN_FULLPATH = CApi.SQLITE_CANTOPEN_FULLPATH;
+ public static final int CANTOPEN_CONVPATH = CApi.SQLITE_CANTOPEN_CONVPATH;
+ public static final int CANTOPEN_SYMLINK = CApi.SQLITE_CANTOPEN_SYMLINK;
+ public static final int CORRUPT_VTAB = CApi.SQLITE_CORRUPT_VTAB;
+ public static final int CORRUPT_SEQUENCE = CApi.SQLITE_CORRUPT_SEQUENCE;
+ public static final int CORRUPT_INDEX = CApi.SQLITE_CORRUPT_INDEX;
+ public static final int READONLY_RECOVERY = CApi.SQLITE_READONLY_RECOVERY;
+ public static final int READONLY_CANTLOCK = CApi.SQLITE_READONLY_CANTLOCK;
+ public static final int READONLY_ROLLBACK = CApi.SQLITE_READONLY_ROLLBACK;
+ public static final int READONLY_DBMOVED = CApi.SQLITE_READONLY_DBMOVED;
+ public static final int READONLY_CANTINIT = CApi.SQLITE_READONLY_CANTINIT;
+ public static final int READONLY_DIRECTORY = CApi.SQLITE_READONLY_DIRECTORY;
+ public static final int ABORT_ROLLBACK = CApi.SQLITE_ABORT_ROLLBACK;
+ public static final int CONSTRAINT_CHECK = CApi.SQLITE_CONSTRAINT_CHECK;
+ public static final int CONSTRAINT_COMMITHOOK = CApi.SQLITE_CONSTRAINT_COMMITHOOK;
+ public static final int CONSTRAINT_FOREIGNKEY = CApi.SQLITE_CONSTRAINT_FOREIGNKEY;
+ public static final int CONSTRAINT_FUNCTION = CApi.SQLITE_CONSTRAINT_FUNCTION;
+ public static final int CONSTRAINT_NOTNULL = CApi.SQLITE_CONSTRAINT_NOTNULL;
+ public static final int CONSTRAINT_PRIMARYKEY = CApi.SQLITE_CONSTRAINT_PRIMARYKEY;
+ public static final int CONSTRAINT_TRIGGER = CApi.SQLITE_CONSTRAINT_TRIGGER;
+ public static final int CONSTRAINT_UNIQUE = CApi.SQLITE_CONSTRAINT_UNIQUE;
+ public static final int CONSTRAINT_VTAB = CApi.SQLITE_CONSTRAINT_VTAB;
+ public static final int CONSTRAINT_ROWID = CApi.SQLITE_CONSTRAINT_ROWID;
+ public static final int CONSTRAINT_PINNED = CApi.SQLITE_CONSTRAINT_PINNED;
+ public static final int CONSTRAINT_DATATYPE = CApi.SQLITE_CONSTRAINT_DATATYPE;
+ public static final int NOTICE_RECOVER_WAL = CApi.SQLITE_NOTICE_RECOVER_WAL;
+ public static final int NOTICE_RECOVER_ROLLBACK = CApi.SQLITE_NOTICE_RECOVER_ROLLBACK;
+ public static final int WARNING_AUTOINDEX = CApi.SQLITE_WARNING_AUTOINDEX;
+ public static final int AUTH_USER = CApi.SQLITE_AUTH_USER;
+ public static final int OK_LOAD_PERMANENTLY = CApi.SQLITE_OK_LOAD_PERMANENTLY;
+
+ // sqlite3_open() flags
+ public static final int OPEN_READWRITE = CApi.SQLITE_OPEN_READWRITE;
+ public static final int OPEN_CREATE = CApi.SQLITE_OPEN_CREATE;
+ public static final int OPEN_EXRESCODE = CApi.SQLITE_OPEN_EXRESCODE;
+
+ // transaction state
+ public static final int TXN_NONE = CApi.SQLITE_TXN_NONE;
+ public static final int TXN_READ = CApi.SQLITE_TXN_READ;
+ public static final int TXN_WRITE = CApi.SQLITE_TXN_WRITE;
+
+ // sqlite3_status() ops
+ public static final int STATUS_MEMORY_USED = CApi.SQLITE_STATUS_MEMORY_USED;
+ public static final int STATUS_PAGECACHE_USED = CApi.SQLITE_STATUS_PAGECACHE_USED;
+ public static final int STATUS_PAGECACHE_OVERFLOW = CApi.SQLITE_STATUS_PAGECACHE_OVERFLOW;
+ public static final int STATUS_MALLOC_SIZE = CApi.SQLITE_STATUS_MALLOC_SIZE;
+ public static final int STATUS_PARSER_STACK = CApi.SQLITE_STATUS_PARSER_STACK;
+ public static final int STATUS_PAGECACHE_SIZE = CApi.SQLITE_STATUS_PAGECACHE_SIZE;
+ public static final int STATUS_MALLOC_COUNT = CApi.SQLITE_STATUS_MALLOC_COUNT;
+
+ // sqlite3_db_status() ops
+ public static final int DBSTATUS_LOOKASIDE_USED = CApi.SQLITE_DBSTATUS_LOOKASIDE_USED;
+ public static final int DBSTATUS_CACHE_USED = CApi.SQLITE_DBSTATUS_CACHE_USED;
+ public static final int DBSTATUS_SCHEMA_USED = CApi.SQLITE_DBSTATUS_SCHEMA_USED;
+ public static final int DBSTATUS_STMT_USED = CApi.SQLITE_DBSTATUS_STMT_USED;
+ public static final int DBSTATUS_LOOKASIDE_HIT = CApi.SQLITE_DBSTATUS_LOOKASIDE_HIT;
+ public static final int DBSTATUS_LOOKASIDE_MISS_SIZE = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE;
+ public static final int DBSTATUS_LOOKASIDE_MISS_FULL = CApi.SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL;
+ public static final int DBSTATUS_CACHE_HIT = CApi.SQLITE_DBSTATUS_CACHE_HIT;
+ public static final int DBSTATUS_CACHE_MISS = CApi.SQLITE_DBSTATUS_CACHE_MISS;
+ public static final int DBSTATUS_CACHE_WRITE = CApi.SQLITE_DBSTATUS_CACHE_WRITE;
+ public static final int DBSTATUS_DEFERRED_FKS = CApi.SQLITE_DBSTATUS_DEFERRED_FKS;
+ public static final int DBSTATUS_CACHE_USED_SHARED = CApi.SQLITE_DBSTATUS_CACHE_USED_SHARED;
+ public static final int DBSTATUS_CACHE_SPILL = CApi.SQLITE_DBSTATUS_CACHE_SPILL;
+
+ // Limits
+ public static final int LIMIT_LENGTH = CApi.SQLITE_LIMIT_LENGTH;
+ public static final int LIMIT_SQL_LENGTH = CApi.SQLITE_LIMIT_SQL_LENGTH;
+ public static final int LIMIT_COLUMN = CApi.SQLITE_LIMIT_COLUMN;
+ public static final int LIMIT_EXPR_DEPTH = CApi.SQLITE_LIMIT_EXPR_DEPTH;
+ public static final int LIMIT_COMPOUND_SELECT = CApi.SQLITE_LIMIT_COMPOUND_SELECT;
+ public static final int LIMIT_VDBE_OP = CApi.SQLITE_LIMIT_VDBE_OP;
+ public static final int LIMIT_FUNCTION_ARG = CApi.SQLITE_LIMIT_FUNCTION_ARG;
+ public static final int LIMIT_ATTACHED = CApi.SQLITE_LIMIT_ATTACHED;
+ public static final int LIMIT_LIKE_PATTERN_LENGTH = CApi.SQLITE_LIMIT_LIKE_PATTERN_LENGTH;
+ public static final int LIMIT_VARIABLE_NUMBER = CApi.SQLITE_LIMIT_VARIABLE_NUMBER;
+ public static final int LIMIT_TRIGGER_DEPTH = CApi.SQLITE_LIMIT_TRIGGER_DEPTH;
+ public static final int LIMIT_WORKER_THREADS = CApi.SQLITE_LIMIT_WORKER_THREADS;
+
+ // sqlite3_prepare_v3() flags
+ public static final int PREPARE_PERSISTENT = CApi.SQLITE_PREPARE_PERSISTENT;
+ public static final int PREPARE_NO_VTAB = CApi.SQLITE_PREPARE_NO_VTAB;
+
+ // sqlite3_trace_v2() flags
+ public static final int TRACE_STMT = CApi.SQLITE_TRACE_STMT;
+ public static final int TRACE_PROFILE = CApi.SQLITE_TRACE_PROFILE;
+ public static final int TRACE_ROW = CApi.SQLITE_TRACE_ROW;
+ public static final int TRACE_CLOSE = CApi.SQLITE_TRACE_CLOSE;
+ public static final int TRACE_ALL = TRACE_STMT | TRACE_PROFILE | TRACE_ROW | TRACE_CLOSE;
+
+ // sqlite3_db_config() ops
+ public static final int DBCONFIG_ENABLE_FKEY = CApi.SQLITE_DBCONFIG_ENABLE_FKEY;
+ public static final int DBCONFIG_ENABLE_TRIGGER = CApi.SQLITE_DBCONFIG_ENABLE_TRIGGER;
+ public static final int DBCONFIG_ENABLE_FTS3_TOKENIZER = CApi.SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER;
+ public static final int DBCONFIG_ENABLE_LOAD_EXTENSION = CApi.SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION;
+ public static final int DBCONFIG_NO_CKPT_ON_CLOSE = CApi.SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE;
+ public static final int DBCONFIG_ENABLE_QPSG = CApi.SQLITE_DBCONFIG_ENABLE_QPSG;
+ public static final int DBCONFIG_TRIGGER_EQP = CApi.SQLITE_DBCONFIG_TRIGGER_EQP;
+ public static final int DBCONFIG_RESET_DATABASE = CApi.SQLITE_DBCONFIG_RESET_DATABASE;
+ public static final int DBCONFIG_DEFENSIVE = CApi.SQLITE_DBCONFIG_DEFENSIVE;
+ public static final int DBCONFIG_WRITABLE_SCHEMA = CApi.SQLITE_DBCONFIG_WRITABLE_SCHEMA;
+ public static final int DBCONFIG_LEGACY_ALTER_TABLE = CApi.SQLITE_DBCONFIG_LEGACY_ALTER_TABLE;
+ public static final int DBCONFIG_DQS_DML = CApi.SQLITE_DBCONFIG_DQS_DML;
+ public static final int DBCONFIG_DQS_DDL = CApi.SQLITE_DBCONFIG_DQS_DDL;
+ public static final int DBCONFIG_ENABLE_VIEW = CApi.SQLITE_DBCONFIG_ENABLE_VIEW;
+ public static final int DBCONFIG_LEGACY_FILE_FORMAT = CApi.SQLITE_DBCONFIG_LEGACY_FILE_FORMAT;
+ public static final int DBCONFIG_TRUSTED_SCHEMA = CApi.SQLITE_DBCONFIG_TRUSTED_SCHEMA;
+ public static final int DBCONFIG_STMT_SCANSTATUS = CApi.SQLITE_DBCONFIG_STMT_SCANSTATUS;
+ public static final int DBCONFIG_REVERSE_SCANORDER = CApi.SQLITE_DBCONFIG_REVERSE_SCANORDER;
+
+ // sqlite3_config() ops
+ public static final int CONFIG_SINGLETHREAD = CApi.SQLITE_CONFIG_SINGLETHREAD;
+ public static final int CONFIG_MULTITHREAD = CApi.SQLITE_CONFIG_MULTITHREAD;
+ public static final int CONFIG_SERIALIZED = CApi.SQLITE_CONFIG_SERIALIZED;
+
+ // Encodings
+ public static final int UTF8 = CApi.SQLITE_UTF8;
+ public static final int UTF16 = CApi.SQLITE_UTF16;
+ public static final int UTF16LE = CApi.SQLITE_UTF16LE;
+ public static final int UTF16BE = CApi.SQLITE_UTF16BE;
+ /* We elide the UTF16_ALIGNED from this interface because it
+ is irrelevant for the Java interface. */
+
+ // SQL data type IDs
+ public static final int INTEGER = CApi.SQLITE_INTEGER;
+ public static final int FLOAT = CApi.SQLITE_FLOAT;
+ public static final int TEXT = CApi.SQLITE_TEXT;
+ public static final int BLOB = CApi.SQLITE_BLOB;
+ public static final int NULL = CApi.SQLITE_NULL;
+
+ // Authorizer codes.
+ public static final int DENY = CApi.SQLITE_DENY;
+ public static final int IGNORE = CApi.SQLITE_IGNORE;
+ public static final int CREATE_INDEX = CApi.SQLITE_CREATE_INDEX;
+ public static final int CREATE_TABLE = CApi.SQLITE_CREATE_TABLE;
+ public static final int CREATE_TEMP_INDEX = CApi.SQLITE_CREATE_TEMP_INDEX;
+ public static final int CREATE_TEMP_TABLE = CApi.SQLITE_CREATE_TEMP_TABLE;
+ public static final int CREATE_TEMP_TRIGGER = CApi.SQLITE_CREATE_TEMP_TRIGGER;
+ public static final int CREATE_TEMP_VIEW = CApi.SQLITE_CREATE_TEMP_VIEW;
+ public static final int CREATE_TRIGGER = CApi.SQLITE_CREATE_TRIGGER;
+ public static final int CREATE_VIEW = CApi.SQLITE_CREATE_VIEW;
+ public static final int DELETE = CApi.SQLITE_DELETE;
+ public static final int DROP_INDEX = CApi.SQLITE_DROP_INDEX;
+ public static final int DROP_TABLE = CApi.SQLITE_DROP_TABLE;
+ public static final int DROP_TEMP_INDEX = CApi.SQLITE_DROP_TEMP_INDEX;
+ public static final int DROP_TEMP_TABLE = CApi.SQLITE_DROP_TEMP_TABLE;
+ public static final int DROP_TEMP_TRIGGER = CApi.SQLITE_DROP_TEMP_TRIGGER;
+ public static final int DROP_TEMP_VIEW = CApi.SQLITE_DROP_TEMP_VIEW;
+ public static final int DROP_TRIGGER = CApi.SQLITE_DROP_TRIGGER;
+ public static final int DROP_VIEW = CApi.SQLITE_DROP_VIEW;
+ public static final int INSERT = CApi.SQLITE_INSERT;
+ public static final int PRAGMA = CApi.SQLITE_PRAGMA;
+ public static final int READ = CApi.SQLITE_READ;
+ public static final int SELECT = CApi.SQLITE_SELECT;
+ public static final int TRANSACTION = CApi.SQLITE_TRANSACTION;
+ public static final int UPDATE = CApi.SQLITE_UPDATE;
+ public static final int ATTACH = CApi.SQLITE_ATTACH;
+ public static final int DETACH = CApi.SQLITE_DETACH;
+ public static final int ALTER_TABLE = CApi.SQLITE_ALTER_TABLE;
+ public static final int REINDEX = CApi.SQLITE_REINDEX;
+ public static final int ANALYZE = CApi.SQLITE_ANALYZE;
+ public static final int CREATE_VTABLE = CApi.SQLITE_CREATE_VTABLE;
+ public static final int DROP_VTABLE = CApi.SQLITE_DROP_VTABLE;
+ public static final int FUNCTION = CApi.SQLITE_FUNCTION;
+ public static final int SAVEPOINT = CApi.SQLITE_SAVEPOINT;
+ public static final int RECURSIVE = CApi.SQLITE_RECURSIVE;
//! Used only by the open() factory functions.
private Sqlite(sqlite3 db){
this.db = db;
}
+ /** Maps org.sqlite.jni.capi.sqlite3 to Sqlite instances. */
+ private static final java.util.Map nativeToWrapper
+ = new java.util.HashMap<>();
+
+
+ /**
+ When any given thread is done using the SQLite library, calling
+ this will free up any native-side resources which may be
+ associated specifically with that thread. This is not strictly
+ necessary, in particular in applications which only use SQLite
+ from a single thread, but may help free some otherwise errant
+ resources.
+
+ Calling into SQLite from a given thread after this has been
+ called in that thread is harmless. The library will simply start
+ to re-cache certain state for that thread.
+
+ Contrariwise, failing to call this will effectively leak a small
+ amount of cached state for the thread, which may add up to
+ significant amounts if the application uses SQLite from many
+ threads.
+
+ This must never be called while actively using SQLite from this
+ thread, e.g. from within a query loop or a callback which is
+ operating on behalf of the library.
+ */
+ static void uncacheThread(){
+ CApi.sqlite3_java_uncache_thread();
+ }
+
+ /**
+ Returns the Sqlite object associated with the given sqlite3
+ object, or null if there is no such mapping.
+ */
+ static Sqlite fromNative(sqlite3 low){
+ synchronized(nativeToWrapper){
+ return nativeToWrapper.get(low);
+ }
+ }
+
/**
Returns a newly-opened db connection or throws SqliteException if
opening fails. All arguments are as documented for
@@ -44,7 +330,7 @@ private Sqlite(sqlite3 db){
*/
public static Sqlite open(String filename, int flags, String vfsName){
final OutputPointer.sqlite3 out = new OutputPointer.sqlite3();
- final int rc = sqlite3_open_v2(filename, out, flags, vfsName);
+ final int rc = CApi.sqlite3_open_v2(filename, out, flags, vfsName);
final sqlite3 n = out.take();
if( 0!=rc ){
if( null==n ) throw new SqliteException(rc);
@@ -52,7 +338,12 @@ public static Sqlite open(String filename, int flags, String vfsName){
n.close();
throw ex;
}
- return new Sqlite(n);
+ final Sqlite rv = new Sqlite(n);
+ synchronized(nativeToWrapper){
+ nativeToWrapper.put(n, rv);
+ }
+ runAutoExtensions(rv);
+ return rv;
}
public static Sqlite open(String filename, int flags){
@@ -60,11 +351,147 @@ public static Sqlite open(String filename, int flags){
}
public static Sqlite open(String filename){
- return open(filename, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, null);
+ return open(filename, OPEN_READWRITE|OPEN_CREATE, null);
+ }
+
+ public static String libVersion(){
+ return CApi.sqlite3_libversion();
+ }
+
+ public static int libVersionNumber(){
+ return CApi.sqlite3_libversion_number();
+ }
+
+ public static String libSourceId(){
+ return CApi.sqlite3_sourceid();
+ }
+
+ /**
+ Returns the value of the native library's build-time value of the
+ SQLITE_THREADSAFE build option.
+ */
+ public static int libThreadsafe(){
+ return CApi.sqlite3_threadsafe();
+ }
+
+ /**
+ Analog to sqlite3_compileoption_get().
+ */
+ public static String compileOptionGet(int n){
+ return CApi.sqlite3_compileoption_get(n);
+ }
+
+ /**
+ Analog to sqlite3_compileoption_used().
+ */
+ public static boolean compileOptionUsed(String optName){
+ return CApi.sqlite3_compileoption_used(optName);
+ }
+
+ private static boolean hasNormalizeSql =
+ compileOptionUsed("ENABLE_NORMALIZE");
+
+ private static boolean hasSqlLog =
+ compileOptionUsed("ENABLE_SQLLOG");
+
+ /**
+ Throws UnsupportedOperationException if check is false.
+ flag is expected to be the name of an SQLITE_ENABLE_...
+ build flag.
+ */
+ private static void checkSupported(boolean check, String flag){
+ if( !check ){
+ throw new UnsupportedOperationException(
+ "Library was built without "+flag
+ );
+ }
+ }
+
+ /**
+ Analog to sqlite3_complete().
+ */
+ public static boolean isCompleteStatement(String sql){
+ switch(CApi.sqlite3_complete(sql)){
+ case 0: return false;
+ case CApi.SQLITE_MISUSE:
+ throw new IllegalArgumentException("Input may not be null.");
+ case CApi.SQLITE_NOMEM:
+ throw new OutOfMemoryError();
+ default:
+ return true;
+ }
+ }
+
+ public static int keywordCount(){
+ return CApi.sqlite3_keyword_count();
+ }
+
+ public static boolean keywordCheck(String word){
+ return CApi.sqlite3_keyword_check(word);
+ }
+
+ public static String keywordName(int index){
+ return CApi.sqlite3_keyword_name(index);
+ }
+
+ public static boolean strglob(String glob, String txt){
+ return 0==CApi.sqlite3_strglob(glob, txt);
+ }
+
+ public static boolean strlike(String glob, String txt, char escChar){
+ return 0==CApi.sqlite3_strlike(glob, txt, escChar);
+ }
+
+ /**
+ Output object for use with status() and libStatus().
+ */
+ public static final class Status {
+ /** The current value for the requested status() or libStatus() metric. */
+ long current;
+ /** The peak value for the requested status() or libStatus() metric. */
+ long peak;
+ };
+
+ /**
+ As per sqlite3_status64(), but returns its current and high-water
+ results as a Status object. Throws if the first argument is
+ not one of the STATUS_... constants.
+ */
+ public static Status libStatus(int op, boolean resetStats){
+ org.sqlite.jni.capi.OutputPointer.Int64 pCurrent =
+ new org.sqlite.jni.capi.OutputPointer.Int64();
+ org.sqlite.jni.capi.OutputPointer.Int64 pHighwater =
+ new org.sqlite.jni.capi.OutputPointer.Int64();
+ checkRcStatic( CApi.sqlite3_status64(op, pCurrent, pHighwater, resetStats) );
+ final Status s = new Status();
+ s.current = pCurrent.value;
+ s.peak = pHighwater.value;
+ return s;
+ }
+
+ /**
+ As per sqlite3_db_status(), but returns its current and
+ high-water results as a Status object. Throws if the first
+ argument is not one of the DBSTATUS_... constants or on any other
+ misuse.
+ */
+ public Status status(int op, boolean resetStats){
+ org.sqlite.jni.capi.OutputPointer.Int32 pCurrent =
+ new org.sqlite.jni.capi.OutputPointer.Int32();
+ org.sqlite.jni.capi.OutputPointer.Int32 pHighwater =
+ new org.sqlite.jni.capi.OutputPointer.Int32();
+ checkRc( CApi.sqlite3_db_status(thisDb(), op, pCurrent, pHighwater, resetStats) );
+ final Status s = new Status();
+ s.current = pCurrent.value;
+ s.peak = pHighwater.value;
+ return s;
}
@Override public void close(){
if(null!=this.db){
+ synchronized(nativeToWrapper){
+ nativeToWrapper.remove(this.db);
+ }
this.db.close();
this.db = null;
}
@@ -77,7 +504,7 @@ public static Sqlite open(String filename){
*/
sqlite3 nativeHandle(){ return this.db; }
- private sqlite3 affirmOpen(){
+ private sqlite3 thisDb(){
if( null==db || 0==db.getNativePointer() ){
throw new IllegalArgumentException("This database instance is closed.");
}
@@ -88,115 +515,207 @@ private sqlite3 affirmOpen(){
// return s==null ? null : s.getBytes(StandardCharsets.UTF_8);
// }
- private void affirmRcOk(int rc){
+ /**
+ If rc!=0, throws an SqliteException. If this db is currently
+ opened and has non-0 sqlite3_errcode(), the error state is
+ extracted from it, else only the string form of rc is used. It is
+ the caller's responsibility to filter out non-error codes such as
+ SQLITE_ROW and SQLITE_DONE before calling this.
+
+ As a special case, if rc is SQLITE_NOMEM, an OutOfMemoryError is
+ thrown.
+ */
+ private void checkRc(int rc){
if( 0!=rc ){
- throw new SqliteException(db);
+ if( CApi.SQLITE_NOMEM==rc ){
+ throw new OutOfMemoryError();
+ }else if( null==db || 0==CApi.sqlite3_errcode(db) ){
+ throw new SqliteException(rc);
+ }else{
+ throw new SqliteException(db);
+ }
}
}
/**
- Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to
- create new instances.
+ Like checkRc() but behaves as if that function were
+ called with a null db object.
*/
- public final class Stmt implements AutoCloseable {
- private Sqlite _db = null;
- private sqlite3_stmt stmt = null;
- /** Only called by the prepare() factory functions. */
- Stmt(Sqlite db, sqlite3_stmt stmt){
- this._db = db;
- this.stmt = stmt;
+ private static void checkRcStatic(int rc){
+ if( 0!=rc ){
+ if( CApi.SQLITE_NOMEM==rc ){
+ throw new OutOfMemoryError();
+ }else{
+ throw new SqliteException(rc);
+ }
}
+ }
- sqlite3_stmt nativeHandle(){
- return stmt;
- }
+ /**
+ Toggles the use of extended result codes on or off. By default
+ they are turned off, but they can be enabled by default by
+ including the OPEN_EXRESCODE flag when opening a database.
- private sqlite3_stmt affirmOpen(){
- if( null==stmt || 0==stmt.getNativePointer() ){
- throw new IllegalArgumentException("This Stmt has been finalized.");
- }
- return stmt;
- }
+ Because this API reports db-side errors using exceptions,
+ enabling this may change the values returned by
+ SqliteException.errcode().
+ */
+ public void useExtendedResultCodes(boolean on){
+ checkRc( CApi.sqlite3_extended_result_codes(thisDb(), on) );
+ }
- /**
- Corresponds to sqlite3_finalize(), but we cannot override the
- name finalize() here because this one requires a different
- signature. It does not throw on error here because "destructors
- do not throw." If it returns non-0, the object is still
- finalized.
- */
- public int finalizeStmt(){
- int rc = 0;
- if( null!=stmt ){
- sqlite3_finalize(stmt);
- stmt = null;
- }
- return rc;
- }
+ /**
+ Analog to sqlite3_prepare_v3(), this prepares the first SQL
+ statement from the given input string and returns it as a
+ Stmt. It throws an SqliteException if preparation fails or an
+ IllegalArgumentException if the input is empty (e.g. contains
+ only comments or whitespace).
- @Override public void close(){
- finalizeStmt();
+ The first argument must be SQL input in UTF-8 encoding.
+
+ prepFlags must be 0 or a bitmask of the PREPARE_... constants.
+
+ For processing multiple statements from a single input, use
+ prepareMulti().
+
+ Design note: though the C-level API succeeds with a null
+ statement object for empty inputs, that approach is cumbersome to
+ use in higher-level APIs because every prepared statement has to
+ be checked for null before using it.
+ */
+ public Stmt prepare(byte utf8Sql[], int prepFlags){
+ final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
+ final int rc = CApi.sqlite3_prepare_v3(thisDb(), utf8Sql, prepFlags, out);
+ checkRc(rc);
+ final sqlite3_stmt q = out.take();
+ if( null==q ){
+ /* The C-level API treats input which is devoid of SQL
+ statements (e.g. all comments or an empty string) as success
+ but returns a NULL sqlite3_stmt object. In higher-level APIs,
+ wrapping a "successful NULL" object that way is tedious to
+ use because it forces clients and/or wrapper-level code to
+ check for that unusual case. In practice, higher-level
+ bindings are generally better-served by treating empty SQL
+ input as an error. */
+ throw new IllegalArgumentException("Input contains no SQL statements.");
}
+ return new Stmt(this, q);
+ }
+ /**
+ Equivalent to prepare(X, prepFlags), where X is
+ sql.getBytes(StandardCharsets.UTF_8).
+ */
+ public Stmt prepare(String sql, int prepFlags){
+ return prepare( sql.getBytes(StandardCharsets.UTF_8), prepFlags );
+ }
+
+ /**
+ Equivalent to prepare(sql, 0).
+ */
+ public Stmt prepare(String sql){
+ return prepare(sql, 0);
+ }
+
+
+ /**
+ Callback type for use with prepareMulti().
+ */
+ public interface PrepareMulti {
/**
- Throws if rc is any value other than 0, SQLITE_ROW, or
- SQLITE_DONE, else returns rc.
+ Gets passed a Stmt which it may handle in arbitrary ways.
+ Ownership of st is passed to this function. It must throw on
+ error.
*/
- private int checkRc(int rc){
- switch(rc){
- case 0:
- case SQLITE_ROW:
- case SQLITE_DONE: return rc;
- default:
- throw new SqliteException(this);
- }
- }
+ void call(Sqlite.Stmt st);
+ }
+ /**
+ A PrepareMulti implementation which calls another PrepareMulti
+ object and then finalizes its statement.
+ */
+ public static class PrepareMultiFinalize implements PrepareMulti {
+ private final PrepareMulti pm;
/**
- Works like sqlite3_step() but throws SqliteException for any
- result other than 0, SQLITE_ROW, or SQLITE_DONE.
+ Proxies the given PrepareMulti via this object's call() method.
*/
- public int step(){
- return checkRc(sqlite3_step(affirmOpen()));
+ public PrepareMultiFinalize(PrepareMulti proxy){
+ this.pm = proxy;
}
-
- public Sqlite db(){ return this._db; }
-
/**
- Works like sqlite3_reset() but throws on error.
+ Passes st to the call() method of the object this one proxies,
+ then finalizes st, propagating any exceptions from call() after
+ finalizing st.
*/
- public void reset(){
- checkRc(sqlite3_reset(affirmOpen()));
+ @Override public void call(Stmt st){
+ try{ pm.call(st); }
+ finally{ st.finalizeStmt(); }
}
+ }
- public void clearBindings(){
- sqlite3_clear_bindings( affirmOpen() );
- }
+ /**
+ Equivalent to prepareMulti(sql,0,visitor).
+ */
+ public void prepareMulti(String sql, PrepareMulti visitor){
+ prepareMulti( sql, 0, visitor );
}
+ /**
+ Equivallent to prepareMulti(X,prepFlags,visitor), where X is
+ sql.getBytes(StandardCharsets.UTF_8).
+ */
+ public void prepareMulti(String sql, int prepFlags, PrepareMulti visitor){
+ prepareMulti(sql.getBytes(StandardCharsets.UTF_8), prepFlags, visitor);
+ }
/**
- prepare() TODOs include:
+ A variant of prepare() which can handle multiple SQL statements
+ in a single input string. For each statement in the given string,
+ the statement is passed to visitor.call() a single time, passing
+ ownership of the statement to that function. This function does
+ not step() or close() statements - those operations are left to
+ caller or the visitor function.
- - overloads taking byte[] and ByteBuffer.
+ Unlike prepare(), this function does not fail if the input
+ contains only whitespace or SQL comments. In that case it is up
+ to the caller to arrange for that to be an error (if desired).
- - multi-statement processing, like CApi.sqlite3_prepare_multi()
- but using a callback specific to the higher-level Stmt class
- rather than the sqlite3_stmt class.
- */
- public Stmt prepare(String sql, int prepFlags){
- final OutputPointer.sqlite3_stmt out = new OutputPointer.sqlite3_stmt();
- final int rc = sqlite3_prepare_v3(affirmOpen(), sql, prepFlags, out);
- affirmRcOk(rc);
- return new Stmt(this, out.take());
- }
+ PrepareMultiFinalize offers a proxy which finalizes each
+ statement after it is passed to another client-defined visitor.
- public Stmt prepare(String sql){
- return prepare(sql, 0);
+ Be aware that certain legal SQL constructs may fail in the
+ preparation phase, before the corresponding statement can be
+ stepped. Most notably, authorizer checks which disallow access to
+ something in a statement behave that way.
+ */
+ public void prepareMulti(byte sqlUtf8[], int prepFlags, PrepareMulti visitor){
+ int pos = 0, n = 1;
+ byte[] sqlChunk = sqlUtf8;
+ final org.sqlite.jni.capi.OutputPointer.sqlite3_stmt outStmt =
+ new org.sqlite.jni.capi.OutputPointer.sqlite3_stmt();
+ final org.sqlite.jni.capi.OutputPointer.Int32 oTail =
+ new org.sqlite.jni.capi.OutputPointer.Int32();
+ while( pos < sqlChunk.length ){
+ sqlite3_stmt stmt = null;
+ if( pos>0 ){
+ sqlChunk = java.util.Arrays.copyOfRange(sqlChunk, pos, sqlChunk.length);
+ }
+ if( 0==sqlChunk.length ) break;
+ checkRc(
+ CApi.sqlite3_prepare_v3(db, sqlChunk, prepFlags, outStmt, oTail)
+ );
+ pos = oTail.value;
+ stmt = outStmt.take();
+ if( null==stmt ){
+ /* empty statement, e.g. only comments or whitespace, was parsed. */
+ continue;
+ }
+ visitor.call(new Stmt(this, stmt));
+ }
}
- public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f ){
- int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep,
+ public void createFunction(String name, int nArg, int eTextRep, ScalarFunction f){
+ int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
new SqlFunction.ScalarAdapter(f));
if( 0!=rc ) throw new SqliteException(db);
}
@@ -205,8 +724,8 @@ public void createFunction(String name, int nArg, ScalarFunction f){
this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
}
- public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f ){
- int rc = CApi.sqlite3_create_function(affirmOpen(), name, nArg, eTextRep,
+ public void createFunction(String name, int nArg, int eTextRep, AggregateFunction f){
+ int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
new SqlFunction.AggregateAdapter(f));
if( 0!=rc ) throw new SqliteException(db);
}
@@ -215,4 +734,1258 @@ public void createFunction(String name, int nArg, AggregateFunction f){
this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
}
+ public void createFunction(String name, int nArg, int eTextRep, WindowFunction f){
+ int rc = CApi.sqlite3_create_function(thisDb(), name, nArg, eTextRep,
+ new SqlFunction.WindowAdapter(f));
+ if( 0!=rc ) throw new SqliteException(db);
+ }
+
+ public void createFunction(String name, int nArg, WindowFunction f){
+ this.createFunction(name, nArg, CApi.SQLITE_UTF8, f);
+ }
+
+ public long changes(){
+ return CApi.sqlite3_changes64(thisDb());
+ }
+
+ public long totalChanges(){
+ return CApi.sqlite3_total_changes64(thisDb());
+ }
+
+ public long lastInsertRowId(){
+ return CApi.sqlite3_last_insert_rowid(thisDb());
+ }
+
+ public void setLastInsertRowId(long rowId){
+ CApi.sqlite3_set_last_insert_rowid(thisDb(), rowId);
+ }
+
+ public void interrupt(){
+ CApi.sqlite3_interrupt(thisDb());
+ }
+
+ public boolean isInterrupted(){
+ return CApi.sqlite3_is_interrupted(thisDb());
+ }
+
+ public boolean isAutoCommit(){
+ return CApi.sqlite3_get_autocommit(thisDb());
+ }
+
+ /**
+ Analog to sqlite3_txn_state(). Returns one of TXN_NONE, TXN_READ,
+ or TXN_WRITE to denote this database's current transaction state
+ for the given schema name (or the most restrictive state of any
+ schema if zSchema is null).
+ */
+ public int transactionState(String zSchema){
+ return CApi.sqlite3_txn_state(thisDb(), zSchema);
+ }
+
+ /**
+ Analog to sqlite3_db_name(). Returns null if passed an unknown
+ index.
+ */
+ public String dbName(int dbNdx){
+ return CApi.sqlite3_db_name(thisDb(), dbNdx);
+ }
+
+ /**
+ Analog to sqlite3_db_filename(). Returns null if passed an
+ unknown db name.
+ */
+ public String dbFileName(String dbName){
+ return CApi.sqlite3_db_filename(thisDb(), dbName);
+ }
+
+ /**
+ Analog to sqlite3_db_config() for the call forms which take one
+ of the boolean-type db configuration flags (namely the
+ DBCONFIG_... constants defined in this class). On success it
+ returns the result of that underlying call. Throws on error.
+ */
+ public boolean dbConfig(int op, boolean on){
+ org.sqlite.jni.capi.OutputPointer.Int32 pOut =
+ new org.sqlite.jni.capi.OutputPointer.Int32();
+ checkRc( CApi.sqlite3_db_config(thisDb(), op, on ? 1 : 0, pOut) );
+ return pOut.get()!=0;
+ }
+
+ /**
+ Analog to the variant of sqlite3_db_config() for configuring the
+ SQLITE_DBCONFIG_MAINDBNAME option. Throws on error.
+ */
+ public void setMainDbName(String name){
+ checkRc(
+ CApi.sqlite3_db_config(thisDb(), CApi.SQLITE_DBCONFIG_MAINDBNAME,
+ name)
+ );
+ }
+
+ /**
+ Analog to sqlite3_db_readonly() but throws an SqliteException
+ with result code SQLITE_NOTFOUND if given an unknown database
+ name.
+ */
+ public boolean readOnly(String dbName){
+ final int rc = CApi.sqlite3_db_readonly(thisDb(), dbName);
+ if( 0==rc ) return false;
+ else if( rc>0 ) return true;
+ throw new SqliteException(CApi.SQLITE_NOTFOUND);
+ }
+
+ /**
+ Analog to sqlite3_db_release_memory().
+ */
+ public void releaseMemory(){
+ CApi.sqlite3_db_release_memory(thisDb());
+ }
+
+ /**
+ Analog to sqlite3_release_memory().
+ */
+ public static int libReleaseMemory(int n){
+ return CApi.sqlite3_release_memory(n);
+ }
+
+ /**
+ Analog to sqlite3_limit(). limitId must be one of the
+ LIMIT_... constants.
+
+ Returns the old limit for the given option. If newLimit is
+ negative, it returns the old limit without modifying the limit.
+
+ If sqlite3_limit() returns a negative value, this function throws
+ an SqliteException with the SQLITE_RANGE result code but no
+ further error info (because that case does not qualify as a
+ db-level error). Such errors may indicate an invalid argument
+ value or an invalid range for newLimit (the underlying function
+ does not differentiate between those).
+ */
+ public int limit(int limitId, int newLimit){
+ final int rc = CApi.sqlite3_limit(thisDb(), limitId, newLimit);
+ if( rc<0 ){
+ throw new SqliteException(CApi.SQLITE_RANGE);
+ }
+ return rc;
+ }
+
+ /**
+ Analog to sqlite3_errstr().
+ */
+ static String errstr(int resultCode){
+ return CApi.sqlite3_errstr(resultCode);
+ }
+
+ /**
+ A wrapper object for use with tableColumnMetadata(). They are
+ created and populated only via that interface.
+ */
+ public final class TableColumnMetadata {
+ Boolean pNotNull = null;
+ Boolean pPrimaryKey = null;
+ Boolean pAutoinc = null;
+ String pzCollSeq = null;
+ String pzDataType = null;
+
+ private TableColumnMetadata(){}
+
+ public String getDataType(){ return pzDataType; }
+ public String getCollation(){ return pzCollSeq; }
+ public boolean isNotNull(){ return pNotNull; }
+ public boolean isPrimaryKey(){ return pPrimaryKey; }
+ public boolean isAutoincrement(){ return pAutoinc; }
+ }
+
+ /**
+ Returns data about a database, table, and (optionally) column
+ (which may be null), as per sqlite3_table_column_metadata().
+ Throws if passed invalid arguments, else returns the result as a
+ new TableColumnMetadata object.
+ */
+ TableColumnMetadata tableColumnMetadata(
+ String zDbName, String zTableName, String zColumnName
+ ){
+ org.sqlite.jni.capi.OutputPointer.String pzDataType
+ = new org.sqlite.jni.capi.OutputPointer.String();
+ org.sqlite.jni.capi.OutputPointer.String pzCollSeq
+ = new org.sqlite.jni.capi.OutputPointer.String();
+ org.sqlite.jni.capi.OutputPointer.Bool pNotNull
+ = new org.sqlite.jni.capi.OutputPointer.Bool();
+ org.sqlite.jni.capi.OutputPointer.Bool pPrimaryKey
+ = new org.sqlite.jni.capi.OutputPointer.Bool();
+ org.sqlite.jni.capi.OutputPointer.Bool pAutoinc
+ = new org.sqlite.jni.capi.OutputPointer.Bool();
+ final int rc = CApi.sqlite3_table_column_metadata(
+ thisDb(), zDbName, zTableName, zColumnName,
+ pzDataType, pzCollSeq, pNotNull, pPrimaryKey, pAutoinc
+ );
+ checkRc(rc);
+ TableColumnMetadata rv = new TableColumnMetadata();
+ rv.pzDataType = pzDataType.value;
+ rv.pzCollSeq = pzCollSeq.value;
+ rv.pNotNull = pNotNull.value;
+ rv.pPrimaryKey = pPrimaryKey.value;
+ rv.pAutoinc = pAutoinc.value;
+ return rv;
+ }
+
+ public interface TraceCallback {
+ /**
+ Called by sqlite3 for various tracing operations, as per
+ sqlite3_trace_v2(). Note that this interface elides the 2nd
+ argument to the native trace callback, as that role is better
+ filled by instance-local state.
+
+
These callbacks may throw, in which case their exceptions are
+ converted to C-level error information.
+
+
The 2nd argument to this function, if non-null, will be a an
+ Sqlite or Sqlite.Stmt object, depending on the first argument
+ (see below).
+
+
The final argument to this function is the "X" argument
+ documented for sqlite3_trace() and sqlite3_trace_v2(). Its type
+ depends on value of the first argument:
+
+
- SQLITE_TRACE_STMT: pNative is a Sqlite.Stmt. pX is a String
+ containing the prepared SQL.
+
+
- SQLITE_TRACE_PROFILE: pNative is a sqlite3_stmt. pX is a Long
+ holding an approximate number of nanoseconds the statement took
+ to run.
+
+
- SQLITE_TRACE_ROW: pNative is a sqlite3_stmt. pX is null.
+
+
- SQLITE_TRACE_CLOSE: pNative is a sqlite3. pX is null.
+ */
+ void call(int traceFlag, Object pNative, Object pX);
+ }
+
+ /**
+ Analog to sqlite3_trace_v2(). traceMask must be a mask of the
+ TRACE_... constants. Pass a null callback to remove tracing.
+
+ Throws on error.
+ */
+ public void trace(int traceMask, TraceCallback callback){
+ final Sqlite self = this;
+ final org.sqlite.jni.capi.TraceV2Callback tc =
+ (null==callback) ? null : new org.sqlite.jni.capi.TraceV2Callback(){
+ @SuppressWarnings("unchecked")
+ @Override public int call(int flag, Object pNative, Object pX){
+ switch(flag){
+ case TRACE_ROW:
+ case TRACE_PROFILE:
+ case TRACE_STMT:
+ callback.call(flag, Sqlite.Stmt.fromNative((sqlite3_stmt)pNative), pX);
+ break;
+ case TRACE_CLOSE:
+ callback.call(flag, self, pX);
+ break;
+ }
+ return 0;
+ }
+ };
+ checkRc( CApi.sqlite3_trace_v2(thisDb(), traceMask, tc) );
+ };
+
+ /**
+ Corresponds to the sqlite3_stmt class. Use Sqlite.prepare() to
+ create new instances.
+ */
+ public static final class Stmt implements AutoCloseable {
+ private Sqlite _db = null;
+ private sqlite3_stmt stmt = null;
+
+ /** Only called by the prepare() factory functions. */
+ Stmt(Sqlite db, sqlite3_stmt stmt){
+ this._db = db;
+ this.stmt = stmt;
+ synchronized(nativeToWrapper){
+ nativeToWrapper.put(this.stmt, this);
+ }
+ }
+
+ sqlite3_stmt nativeHandle(){
+ return stmt;
+ }
+
+ /** Maps org.sqlite.jni.capi.sqlite3_stmt to Stmt instances. */
+ private static final java.util.Map nativeToWrapper
+ = new java.util.HashMap<>();
+
+ /**
+ Returns the Stmt object associated with the given sqlite3_stmt
+ object, or null if there is no such mapping.
+ */
+ static Stmt fromNative(sqlite3_stmt low){
+ synchronized(nativeToWrapper){
+ return nativeToWrapper.get(low);
+ }
+ }
+
+ /**
+ If this statement is still opened, its low-level handle is
+ returned, else an IllegalArgumentException is thrown.
+ */
+ private sqlite3_stmt thisStmt(){
+ if( null==stmt || 0==stmt.getNativePointer() ){
+ throw new IllegalArgumentException("This Stmt has been finalized.");
+ }
+ return stmt;
+ }
+
+ /** Throws if n is out of range of this statement's result column
+ count. Intended to be used by the columnXyz() methods. */
+ private sqlite3_stmt checkColIndex(int n){
+ if(n<0 || n>=columnCount()){
+ throw new IllegalArgumentException("Column index "+n+" is out of range.");
+ }
+ return thisStmt();
+ }
+
+ /**
+ Corresponds to sqlite3_finalize(), but we cannot override the
+ name finalize() here because this one requires a different
+ signature. It does not throw on error here because "destructors
+ do not throw." If it returns non-0, the object is still
+ finalized, but the result code is an indication that something
+ went wrong in a prior call into the statement's API, as
+ documented for sqlite3_finalize().
+ */
+ public int finalizeStmt(){
+ int rc = 0;
+ if( null!=stmt ){
+ synchronized(nativeToWrapper){
+ nativeToWrapper.remove(this.stmt);
+ }
+ CApi.sqlite3_finalize(stmt);
+ stmt = null;
+ _db = null;
+ }
+ return rc;
+ }
+
+ @Override public void close(){
+ finalizeStmt();
+ }
+
+ /**
+ Throws if rc is any value other than 0, SQLITE_ROW, or
+ SQLITE_DONE, else returns rc. Error state for the exception is
+ extracted from this statement object (if it's opened) or the
+ string form of rc.
+ */
+ private int checkRc(int rc){
+ switch(rc){
+ case 0:
+ case CApi.SQLITE_ROW:
+ case CApi.SQLITE_DONE: return rc;
+ default:
+ if( null==stmt ) throw new SqliteException(rc);
+ else throw new SqliteException(this);
+ }
+ }
+
+ /**
+ Works like sqlite3_step() but returns true for SQLITE_ROW,
+ false for SQLITE_DONE, and throws SqliteException for any other
+ result.
+ */
+ public boolean step(){
+ switch(checkRc(CApi.sqlite3_step(thisStmt()))){
+ case CApi.SQLITE_ROW: return true;
+ case CApi.SQLITE_DONE: return false;
+ default:
+ throw new IllegalStateException(
+ "This \"cannot happen\": all possible result codes were checked already."
+ );
+ }
+ }
+
+ /**
+ Works like sqlite3_step(), returning the same result codes as
+ that function unless throwOnError is true, in which case it
+ will throw an SqliteException for any result codes other than
+ Sqlite.ROW or Sqlite.DONE.
+
+ The utility of this overload over the no-argument one is the
+ ability to handle BUSY and LOCKED errors more easily.
+ */
+ public int step(boolean throwOnError){
+ final int rc = (null==stmt)
+ ? Sqlite.MISUSE
+ : CApi.sqlite3_step(stmt);
+ return throwOnError ? checkRc(rc) : rc;
+ }
+
+ /**
+ Returns the Sqlite which prepared this statement, or null if
+ this statement has been finalized.
+ */
+ public Sqlite getDb(){ return this._db; }
+
+ /**
+ Works like sqlite3_reset() but throws on error.
+ */
+ public void reset(){
+ checkRc(CApi.sqlite3_reset(thisStmt()));
+ }
+
+ public boolean isBusy(){
+ return CApi.sqlite3_stmt_busy(thisStmt());
+ }
+
+ public boolean isReadOnly(){
+ return CApi.sqlite3_stmt_readonly(thisStmt());
+ }
+
+ public String sql(){
+ return CApi.sqlite3_sql(thisStmt());
+ }
+
+ public String expandedSql(){
+ return CApi.sqlite3_expanded_sql(thisStmt());
+ }
+
+ /**
+ Analog to sqlite3_stmt_explain() but throws if op is invalid.
+ */
+ public void explain(int op){
+ checkRc(CApi.sqlite3_stmt_explain(thisStmt(), op));
+ }
+
+ /**
+ Analog to sqlite3_stmt_isexplain().
+ */
+ public int isExplain(){
+ return CApi.sqlite3_stmt_isexplain(thisStmt());
+ }
+
+ /**
+ Analog to sqlite3_normalized_sql(), but throws
+ UnsupportedOperationException if the library was built without
+ the SQLITE_ENABLE_NORMALIZE flag.
+ */
+ public String normalizedSql(){
+ Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_NORMALIZE");
+ return CApi.sqlite3_normalized_sql(thisStmt());
+ }
+
+ public void clearBindings(){
+ CApi.sqlite3_clear_bindings( thisStmt() );
+ }
+ public void bindInt(int ndx, int val){
+ checkRc(CApi.sqlite3_bind_int(thisStmt(), ndx, val));
+ }
+ public void bindInt64(int ndx, long val){
+ checkRc(CApi.sqlite3_bind_int64(thisStmt(), ndx, val));
+ }
+ public void bindDouble(int ndx, double val){
+ checkRc(CApi.sqlite3_bind_double(thisStmt(), ndx, val));
+ }
+ public void bindObject(int ndx, Object o){
+ checkRc(CApi.sqlite3_bind_java_object(thisStmt(), ndx, o));
+ }
+ public void bindNull(int ndx){
+ checkRc(CApi.sqlite3_bind_null(thisStmt(), ndx));
+ }
+ public int bindParameterCount(){
+ return CApi.sqlite3_bind_parameter_count(thisStmt());
+ }
+ public int bindParameterIndex(String paramName){
+ return CApi.sqlite3_bind_parameter_index(thisStmt(), paramName);
+ }
+ public String bindParameterName(int ndx){
+ return CApi.sqlite3_bind_parameter_name(thisStmt(), ndx);
+ }
+ public void bindText(int ndx, byte[] utf8){
+ checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, utf8));
+ }
+ public void bindText(int ndx, String asUtf8){
+ checkRc(CApi.sqlite3_bind_text(thisStmt(), ndx, asUtf8));
+ }
+ public void bindText16(int ndx, byte[] utf16){
+ checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, utf16));
+ }
+ public void bindText16(int ndx, String asUtf16){
+ checkRc(CApi.sqlite3_bind_text16(thisStmt(), ndx, asUtf16));
+ }
+ public void bindZeroBlob(int ndx, int n){
+ checkRc(CApi.sqlite3_bind_zeroblob(thisStmt(), ndx, n));
+ }
+ public void bindBlob(int ndx, byte[] bytes){
+ checkRc(CApi.sqlite3_bind_blob(thisStmt(), ndx, bytes));
+ }
+
+ public byte[] columnBlob(int ndx){
+ return CApi.sqlite3_column_blob( checkColIndex(ndx), ndx );
+ }
+ public byte[] columnText(int ndx){
+ return CApi.sqlite3_column_text( checkColIndex(ndx), ndx );
+ }
+ public String columnText16(int ndx){
+ return CApi.sqlite3_column_text16( checkColIndex(ndx), ndx );
+ }
+ public int columnBytes(int ndx){
+ return CApi.sqlite3_column_bytes( checkColIndex(ndx), ndx );
+ }
+ public int columnBytes16(int ndx){
+ return CApi.sqlite3_column_bytes16( checkColIndex(ndx), ndx );
+ }
+ public int columnInt(int ndx){
+ return CApi.sqlite3_column_int( checkColIndex(ndx), ndx );
+ }
+ public long columnInt64(int ndx){
+ return CApi.sqlite3_column_int64( checkColIndex(ndx), ndx );
+ }
+ public double columnDouble(int ndx){
+ return CApi.sqlite3_column_double( checkColIndex(ndx), ndx );
+ }
+ public int columnType(int ndx){
+ return CApi.sqlite3_column_type( checkColIndex(ndx), ndx );
+ }
+ public String columnDeclType(int ndx){
+ return CApi.sqlite3_column_decltype( checkColIndex(ndx), ndx );
+ }
+ /**
+ Analog to sqlite3_column_count() but throws if this statement
+ has been finalized.
+ */
+ public int columnCount(){
+ /* We cannot reliably cache the column count in a class
+ member because an ALTER TABLE from a separate statement
+ can invalidate that count and we have no way, short of
+ installing a COMMIT handler or the like, of knowing when
+ to re-read it. We cannot install such a handler without
+ interfering with a client's ability to do so. */
+ return CApi.sqlite3_column_count(thisStmt());
+ }
+ public int columnDataCount(){
+ return CApi.sqlite3_data_count( thisStmt() );
+ }
+ public Object columnObject(int ndx){
+ return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx );
+ }
+ public T columnObject(int ndx, Class type){
+ return CApi.sqlite3_column_java_object( checkColIndex(ndx), ndx, type );
+ }
+ public String columnName(int ndx){
+ return CApi.sqlite3_column_name( checkColIndex(ndx), ndx );
+ }
+ public String columnDatabaseName(int ndx){
+ return CApi.sqlite3_column_database_name( checkColIndex(ndx), ndx );
+ }
+ public String columnOriginName(int ndx){
+ return CApi.sqlite3_column_origin_name( checkColIndex(ndx), ndx );
+ }
+ public String columnTableName(int ndx){
+ return CApi.sqlite3_column_table_name( checkColIndex(ndx), ndx );
+ }
+ } /* Stmt class */
+
+ /**
+ Interface for auto-extensions, as per the
+ sqlite3_auto_extension() API.
+
+ Design note: the chicken/egg timing of auto-extension execution
+ requires that this feature be entirely re-implemented in Java
+ because the C-level API has no access to the Sqlite type so
+ cannot pass on an object of that type while the database is being
+ opened. One side effect of this reimplementation is that this
+ class's list of auto-extensions is 100% independent of the
+ C-level list so, e.g., clearAutoExtensions() will have no effect
+ on auto-extensions added via the C-level API and databases opened
+ from that level of API will not be passed to this level's
+ AutoExtension instances.
+ */
+ public interface AutoExtension {
+ public void call(Sqlite db);
+ }
+
+ private static final java.util.Set autoExtensions =
+ new java.util.LinkedHashSet<>();
+
+ /**
+ Passes db to all auto-extensions. If any one of them throws,
+ db.close() is called before the exception is propagated.
+ */
+ private static void runAutoExtensions(Sqlite db){
+ AutoExtension list[];
+ synchronized(autoExtensions){
+ /* Avoid that modifications to the AutoExtension list from within
+ auto-extensions affect this execution of this list. */
+ list = autoExtensions.toArray(new AutoExtension[0]);
+ }
+ try {
+ for( AutoExtension ax : list ) ax.call(db);
+ }catch(Exception e){
+ db.close();
+ throw e;
+ }
+ }
+
+ /**
+ Analog to sqlite3_auto_extension(), adds the given object to the
+ list of auto-extensions if it is not already in that list. The
+ given object will be run as part of Sqlite.open(), and passed the
+ being-opened database. If the extension throws then open() will
+ fail.
+
+ This API does not guaranty whether or not manipulations made to
+ the auto-extension list from within auto-extension callbacks will
+ affect the current traversal of the auto-extension list. Whether
+ or not they do is unspecified and subject to change between
+ versions. e.g. if an AutoExtension calls addAutoExtension(),
+ whether or not the new extension will be run on the being-opened
+ database is undefined.
+
+ Note that calling Sqlite.open() from an auto-extension will
+ necessarily result in recursion loop and (eventually) a stack
+ overflow.
+ */
+ public static void addAutoExtension( AutoExtension e ){
+ if( null==e ){
+ throw new IllegalArgumentException("AutoExtension may not be null.");
+ }
+ synchronized(autoExtensions){
+ autoExtensions.add(e);
+ }
+ }
+
+ /**
+ Removes the given object from the auto-extension list if it is in
+ that list, otherwise this has no side-effects beyond briefly
+ locking that list.
+ */
+ public static void removeAutoExtension( AutoExtension e ){
+ synchronized(autoExtensions){
+ autoExtensions.remove(e);
+ }
+ }
+
+ /**
+ Removes all auto-extensions which were added via addAutoExtension().
+ */
+ public static void clearAutoExtensions(){
+ synchronized(autoExtensions){
+ autoExtensions.clear();
+ }
+ }
+
+ /**
+ Encapsulates state related to the sqlite3 backup API. Use
+ Sqlite.initBackup() to create new instances.
+ */
+ public static final class Backup implements AutoCloseable {
+ private sqlite3_backup b = null;
+ private Sqlite dbTo = null;
+ private Sqlite dbFrom = null;
+
+ Backup(Sqlite dbDest, String schemaDest,Sqlite dbSrc, String schemaSrc){
+ this.dbTo = dbDest;
+ this.dbFrom = dbSrc;
+ b = CApi.sqlite3_backup_init(dbDest.nativeHandle(), schemaDest,
+ dbSrc.nativeHandle(), schemaSrc);
+ if(null==b) toss();
+ }
+
+ private void toss(){
+ int rc = CApi.sqlite3_errcode(dbTo.nativeHandle());
+ if(0!=rc) throw new SqliteException(dbTo);
+ rc = CApi.sqlite3_errcode(dbFrom.nativeHandle());
+ if(0!=rc) throw new SqliteException(dbFrom);
+ throw new SqliteException(CApi.SQLITE_ERROR);
+ }
+
+ private sqlite3_backup getNative(){
+ if( null==b ) throw new IllegalStateException("This Backup is already closed.");
+ return b;
+ }
+ /**
+ If this backup is still active, this completes the backup and
+ frees its native resources, otherwise it this is a no-op.
+ */
+ public void finish(){
+ if( null!=b ){
+ CApi.sqlite3_backup_finish(b);
+ b = null;
+ dbTo = null;
+ dbFrom = null;
+ }
+ }
+
+ /** Equivalent to finish(). */
+ @Override public void close(){
+ this.finish();
+ }
+
+ /**
+ Analog to sqlite3_backup_step(). Returns 0 if stepping succeeds
+ or, Sqlite.DONE if the end is reached, Sqlite.BUSY if one of
+ the databases is busy, Sqlite.LOCKED if one of the databases is
+ locked, and throws for any other result code or if this object
+ has been closed. Note that BUSY and LOCKED are not necessarily
+ permanent errors, so do not trigger an exception.
+ */
+ public int step(int pageCount){
+ final int rc = CApi.sqlite3_backup_step(getNative(), pageCount);
+ switch(rc){
+ case 0:
+ case Sqlite.DONE:
+ case Sqlite.BUSY:
+ case Sqlite.LOCKED:
+ return rc;
+ default:
+ toss();
+ return CApi.SQLITE_ERROR/*not reached*/;
+ }
+ }
+
+ /**
+ Analog to sqlite3_backup_pagecount().
+ */
+ public int pageCount(){
+ return CApi.sqlite3_backup_pagecount(getNative());
+ }
+
+ /**
+ Analog to sqlite3_backup_remaining().
+ */
+ public int remaining(){
+ return CApi.sqlite3_backup_remaining(getNative());
+ }
+ }
+
+ /**
+ Analog to sqlite3_backup_init(). If schemaSrc is null, "main" is
+ assumed. Throws if either this db or dbSrc (the source db) are
+ not opened, if either of schemaDest or schemaSrc are null, or if
+ the underlying call to sqlite3_backup_init() fails.
+
+ The returned object must eventually be cleaned up by either
+ arranging for it to be auto-closed (e.g. using
+ try-with-resources) or by calling its finish() method.
+ */
+ public Backup initBackup(String schemaDest, Sqlite dbSrc, String schemaSrc){
+ thisDb();
+ dbSrc.thisDb();
+ if( null==schemaSrc || null==schemaDest ){
+ throw new IllegalArgumentException(
+ "Neither the source nor destination schema name may be null."
+ );
+ }
+ return new Backup(this, schemaDest, dbSrc, schemaSrc);
+ }
+
+
+ /**
+ Callback type for use with createCollation().
+ */
+ public interface Collation {
+ /**
+ Called by the SQLite core to compare inputs. Implementations
+ must compare its two arguments using memcmp(3) semantics.
+
+ Warning: the SQLite core has no mechanism for reporting errors
+ from custom collations and its workflow does not accommodate
+ propagation of exceptions from callbacks. Any exceptions thrown
+ from collations will be silently supressed and sorting results
+ will be unpredictable.
+ */
+ int call(byte[] lhs, byte[] rhs);
+ }
+
+ /**
+ Analog to sqlite3_create_collation().
+
+ Throws if name is null or empty, c is null, or the encoding flag
+ is invalid. The encoding must be one of the UTF8, UTF16, UTF16LE,
+ or UTF16BE constants.
+ */
+ public void createCollation(String name, int encoding, Collation c){
+ thisDb();
+ if( null==name || 0==name.length()){
+ throw new IllegalArgumentException("Collation name may not be null or empty.");
+ }
+ if( null==c ){
+ throw new IllegalArgumentException("Collation may not be null.");
+ }
+ switch(encoding){
+ case UTF8:
+ case UTF16:
+ case UTF16LE:
+ case UTF16BE:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid Collation encoding.");
+ }
+ checkRc(
+ CApi.sqlite3_create_collation(
+ thisDb(), name, encoding, new org.sqlite.jni.capi.CollationCallback(){
+ @Override public int call(byte[] lhs, byte[] rhs){
+ try{return c.call(lhs, rhs);}
+ catch(Exception e){return 0;}
+ }
+ @Override public void xDestroy(){}
+ }
+ )
+ );
+ }
+
+ /**
+ Callback for use with onCollationNeeded().
+ */
+ public interface CollationNeeded {
+ /**
+ Must behave as documented for the callback for
+ sqlite3_collation_needed().
+
+ Warning: the C API has no mechanism for reporting or
+ propagating errors from this callback, so any exceptions it
+ throws are suppressed.
+ */
+ void call(Sqlite db, int encoding, String collationName);
+ }
+
+ /**
+ Sets up the given object to be called by the SQLite core when it
+ encounters a collation name which it does not know. Pass a null
+ object to disconnect the object from the core. This replaces any
+ existing collation-needed loader, or is a no-op if the given
+ object is already registered. Throws if registering the loader
+ fails.
+ */
+ public void onCollationNeeded( CollationNeeded cn ){
+ org.sqlite.jni.capi.CollationNeededCallback cnc = null;
+ if( null!=cn ){
+ cnc = new org.sqlite.jni.capi.CollationNeededCallback(){
+ @Override public void call(sqlite3 db, int encoding, String collationName){
+ final Sqlite xdb = Sqlite.fromNative(db);
+ if(null!=xdb) cn.call(xdb, encoding, collationName);
+ }
+ };
+ }
+ checkRc( CApi.sqlite3_collation_needed(thisDb(), cnc) );
+ }
+
+ /**
+ Callback for use with busyHandler().
+ */
+ public interface BusyHandler {
+ /**
+ Must function as documented for the C-level
+ sqlite3_busy_handler() callback argument, minus the (void*)
+ argument the C-level function requires.
+
+ If this function throws, it is translated to a database-level
+ error.
+ */
+ int call(int n);
+ }
+
+ /**
+ Analog to sqlite3_busy_timeout().
+ */
+ public void setBusyTimeout(int ms){
+ checkRc(CApi.sqlite3_busy_timeout(thisDb(), ms));
+ }
+
+ /**
+ Analog to sqlite3_busy_handler(). If b is null then any
+ current handler is cleared.
+ */
+ public void setBusyHandler( BusyHandler b ){
+ org.sqlite.jni.capi.BusyHandlerCallback bhc = null;
+ if( null!=b ){
+ bhc = new org.sqlite.jni.capi.BusyHandlerCallback(){
+ @Override public int call(int n){
+ return b.call(n);
+ }
+ };
+ }
+ checkRc( CApi.sqlite3_busy_handler(thisDb(), bhc) );
+ }
+
+ public interface CommitHook {
+ /**
+ Must behave as documented for the C-level sqlite3_commit_hook()
+ callback. If it throws, the exception is translated into
+ a db-level error.
+ */
+ int call();
+ }
+
+ /**
+ A level of indirection to permit setCommitHook() to have similar
+ semantics as the C API, returning the previous hook. The caveat
+ is that if the low-level API is used to install a hook, it will
+ have a different hook type than Sqlite.CommitHook so
+ setCommitHook() will return null instead of that object.
+ */
+ private static class CommitHookProxy
+ implements org.sqlite.jni.capi.CommitHookCallback {
+ final CommitHook commitHook;
+ CommitHookProxy(CommitHook ch){
+ this.commitHook = ch;
+ }
+ @Override public int call(){
+ return commitHook.call();
+ }
+ }
+
+ /**
+ Analog to sqlite3_commit_hook(). Returns the previous hook, if
+ any (else null). Throws if this db is closed.
+
+ Minor caveat: if a commit hook is set on this object's underlying
+ db handle using the lower-level SQLite API, this function may
+ return null when replacing it, despite there being a hook,
+ because it will have a different callback type. So long as the
+ handle is only manipulated via the high-level API, this caveat
+ does not apply.
+ */
+ public CommitHook setCommitHook( CommitHook c ){
+ CommitHookProxy chp = null;
+ if( null!=c ){
+ chp = new CommitHookProxy(c);
+ }
+ final org.sqlite.jni.capi.CommitHookCallback rv =
+ CApi.sqlite3_commit_hook(thisDb(), chp);
+ return (rv instanceof CommitHookProxy)
+ ? ((CommitHookProxy)rv).commitHook
+ : null;
+ }
+
+
+ public interface RollbackHook {
+ /**
+ Must behave as documented for the C-level sqlite3_rollback_hook()
+ callback. If it throws, the exception is translated into
+ a db-level error.
+ */
+ void call();
+ }
+
+ /**
+ A level of indirection to permit setRollbackHook() to have similar
+ semantics as the C API, returning the previous hook. The caveat
+ is that if the low-level API is used to install a hook, it will
+ have a different hook type than Sqlite.RollbackHook so
+ setRollbackHook() will return null instead of that object.
+ */
+ private static class RollbackHookProxy
+ implements org.sqlite.jni.capi.RollbackHookCallback {
+ final RollbackHook rollbackHook;
+ RollbackHookProxy(RollbackHook ch){
+ this.rollbackHook = ch;
+ }
+ @Override public void call(){rollbackHook.call();}
+ }
+
+ /**
+ Analog to sqlite3_rollback_hook(). Returns the previous hook, if
+ any (else null). Throws if this db is closed.
+
+ Minor caveat: if a rollback hook is set on this object's underlying
+ db handle using the lower-level SQLite API, this function may
+ return null when replacing it, despite there being a hook,
+ because it will have a different callback type. So long as the
+ handle is only manipulated via the high-level API, this caveat
+ does not apply.
+ */
+ public RollbackHook setRollbackHook( RollbackHook c ){
+ RollbackHookProxy chp = null;
+ if( null!=c ){
+ chp = new RollbackHookProxy(c);
+ }
+ final org.sqlite.jni.capi.RollbackHookCallback rv =
+ CApi.sqlite3_rollback_hook(thisDb(), chp);
+ return (rv instanceof RollbackHookProxy)
+ ? ((RollbackHookProxy)rv).rollbackHook
+ : null;
+ }
+
+ public interface UpdateHook {
+ /**
+ Must function as described for the C-level sqlite3_update_hook()
+ callback.
+ */
+ void call(int opId, String dbName, String tableName, long rowId);
+ }
+
+ /**
+ A level of indirection to permit setUpdateHook() to have similar
+ semantics as the C API, returning the previous hook. The caveat
+ is that if the low-level API is used to install a hook, it will
+ have a different hook type than Sqlite.UpdateHook so
+ setUpdateHook() will return null instead of that object.
+ */
+ private static class UpdateHookProxy
+ implements org.sqlite.jni.capi.UpdateHookCallback {
+ final UpdateHook updateHook;
+ UpdateHookProxy(UpdateHook ch){
+ this.updateHook = ch;
+ }
+ @Override public void call(int opId, String dbName, String tableName, long rowId){
+ updateHook.call(opId, dbName, tableName, rowId);
+ }
+ }
+
+ /**
+ Analog to sqlite3_update_hook(). Returns the previous hook, if
+ any (else null). Throws if this db is closed.
+
+ Minor caveat: if a update hook is set on this object's underlying
+ db handle using the lower-level SQLite API, this function may
+ return null when replacing it, despite there being a hook,
+ because it will have a different callback type. So long as the
+ handle is only manipulated via the high-level API, this caveat
+ does not apply.
+ */
+ public UpdateHook setUpdateHook( UpdateHook c ){
+ UpdateHookProxy chp = null;
+ if( null!=c ){
+ chp = new UpdateHookProxy(c);
+ }
+ final org.sqlite.jni.capi.UpdateHookCallback rv =
+ CApi.sqlite3_update_hook(thisDb(), chp);
+ return (rv instanceof UpdateHookProxy)
+ ? ((UpdateHookProxy)rv).updateHook
+ : null;
+ }
+
+
+ /**
+ Callback interface for use with setProgressHandler().
+ */
+ public interface ProgressHandler {
+ /**
+ Must behave as documented for the C-level sqlite3_progress_handler()
+ callback. If it throws, the exception is translated into
+ a db-level error.
+ */
+ int call();
+ }
+
+ /**
+ Analog to sqlite3_progress_handler(), sets the current progress
+ handler or clears it if p is null.
+
+ Note that this API, in contrast to setUpdateHook(),
+ setRollbackHook(), and setCommitHook(), cannot return the
+ previous handler. That inconsistency is part of the lower-level C
+ API.
+ */
+ public void setProgressHandler( int n, ProgressHandler p ){
+ org.sqlite.jni.capi.ProgressHandlerCallback phc = null;
+ if( null!=p ){
+ phc = new org.sqlite.jni.capi.ProgressHandlerCallback(){
+ @Override public int call(){ return p.call(); }
+ };
+ }
+ CApi.sqlite3_progress_handler( thisDb(), n, phc );
+ }
+
+
+ /**
+ Callback for use with setAuthorizer().
+ */
+ public interface Authorizer {
+ /**
+ Must function as described for the C-level
+ sqlite3_set_authorizer() callback. If it throws, the error is
+ converted to a db-level error and the exception is suppressed.
+ */
+ int call(int opId, String s1, String s2, String s3, String s4);
+ }
+
+ /**
+ Analog to sqlite3_set_authorizer(), this sets the current
+ authorizer callback, or clears if it passed null.
+ */
+ public void setAuthorizer( Authorizer a ) {
+ org.sqlite.jni.capi.AuthorizerCallback ac = null;
+ if( null!=a ){
+ ac = new org.sqlite.jni.capi.AuthorizerCallback(){
+ @Override public int call(int opId, String s1, String s2, String s3, String s4){
+ return a.call(opId, s1, s2, s3, s4);
+ }
+ };
+ }
+ checkRc( CApi.sqlite3_set_authorizer( thisDb(), ac ) );
+ }
+
+ /**
+ Object type for use with blobOpen()
+ */
+ public final class Blob implements AutoCloseable {
+ private Sqlite db;
+ private sqlite3_blob b;
+ Blob(Sqlite db, sqlite3_blob b){
+ this.db = db;
+ this.b = b;
+ }
+
+ /**
+ If this blob is still opened, its low-level handle is
+ returned, else an IllegalArgumentException is thrown.
+ */
+ private sqlite3_blob thisBlob(){
+ if( null==b || 0==b.getNativePointer() ){
+ throw new IllegalArgumentException("This Blob has been finalized.");
+ }
+ return b;
+ }
+
+ /**
+ Analog to sqlite3_blob_close().
+ */
+ @Override public void close(){
+ if( null!=b ){
+ CApi.sqlite3_blob_close(b);
+ b = null;
+ db = null;
+ }
+ }
+
+ /**
+ Throws if the JVM does not have JNI-level support for
+ ByteBuffer.
+ */
+ private void checkNio(){
+ if( !Sqlite.JNI_SUPPORTS_NIO ){
+ throw new UnsupportedOperationException(
+ "This JVM does not support JNI access to ByteBuffer."
+ );
+ }
+ }
+ /**
+ Analog to sqlite3_blob_reopen() but throws on error.
+ */
+ public void reopen(long newRowId){
+ db.checkRc( CApi.sqlite3_blob_reopen(thisBlob(), newRowId) );
+ }
+
+ /**
+ Analog to sqlite3_blob_write() but throws on error.
+ */
+ public void write( byte[] bytes, int atOffset ){
+ db.checkRc( CApi.sqlite3_blob_write(thisBlob(), bytes, atOffset) );
+ }
+
+ /**
+ Analog to sqlite3_blob_read() but throws on error.
+ */
+ public void read( byte[] dest, int atOffset ){
+ db.checkRc( CApi.sqlite3_blob_read(thisBlob(), dest, atOffset) );
+ }
+
+ /**
+ Analog to sqlite3_blob_bytes().
+ */
+ public int bytes(){
+ return CApi.sqlite3_blob_bytes(thisBlob());
+ }
+ }
+
+ /**
+ Analog to sqlite3_blob_open(). Returns a Blob object for the
+ given database, table, column, and rowid. The blob is opened for
+ read-write mode if writeable is true, else it is read-only.
+
+ The returned object must eventually be freed, before this
+ database is closed, by either arranging for it to be auto-closed
+ or calling its close() method.
+
+ Throws on error.
+ */
+ public Blob blobOpen(String dbName, String tableName, String columnName,
+ long iRow, boolean writeable){
+ final OutputPointer.sqlite3_blob out = new OutputPointer.sqlite3_blob();
+ checkRc(
+ CApi.sqlite3_blob_open(thisDb(), dbName, tableName, columnName,
+ iRow, writeable ? 1 : 0, out)
+ );
+ return new Blob(this, out.take());
+ }
+
+ /**
+ Callback for use with libConfigLog().
+ */
+ public interface ConfigLog {
+ /**
+ Must function as described for a C-level callback for
+ sqlite3_config()'s SQLITE_CONFIG_LOG callback, with the slight
+ signature change. Any exceptions thrown from this callback are
+ necessarily suppressed.
+ */
+ void call(int errCode, String msg);
+ }
+
+ /**
+ Analog to sqlite3_config() with the SQLITE_CONFIG_LOG option,
+ this sets or (if log is null) clears the current logger.
+ */
+ public static void libConfigLog(ConfigLog log){
+ final org.sqlite.jni.capi.ConfigLogCallback l =
+ null==log
+ ? null
+ : new org.sqlite.jni.capi.ConfigLogCallback() {
+ @Override public void call(int errCode, String msg){
+ log.call(errCode, msg);
+ }
+ };
+ checkRcStatic(CApi.sqlite3_config(l));
+ }
+
+ /**
+ Callback for use with libConfigSqlLog().
+ */
+ public interface ConfigSqlLog {
+ /**
+ Must function as described for a C-level callback for
+ sqlite3_config()'s SQLITE_CONFIG_SQLLOG callback, with the
+ slight signature change. Any exceptions thrown from this
+ callback are necessarily suppressed.
+ */
+ void call(Sqlite db, String msg, int msgType);
+ }
+
+ /**
+ Analog to sqlite3_config() with the SQLITE_CONFIG_SQLLOG option,
+ this sets or (if log is null) clears the current logger.
+
+ If SQLite is built without SQLITE_ENABLE_SQLLOG defined then this
+ will throw an UnsupportedOperationException.
+ */
+ public static void libConfigSqlLog(ConfigSqlLog log){
+ Sqlite.checkSupported(hasNormalizeSql, "SQLITE_ENABLE_SQLLOG");
+ final org.sqlite.jni.capi.ConfigSqlLogCallback l =
+ null==log
+ ? null
+ : new org.sqlite.jni.capi.ConfigSqlLogCallback() {
+ @Override public void call(sqlite3 db, String msg, int msgType){
+ try{
+ log.call(fromNative(db), msg, msgType);
+ }catch(Exception e){
+ /* Suppressed */
+ }
+ }
+ };
+ checkRcStatic(CApi.sqlite3_config(l));
+ }
+
+ /**
+ Analog to the C-level sqlite3_config() with one of the
+ SQLITE_CONFIG_... constants defined as CONFIG_... in this
+ class. Throws on error, including passing of an unknown option or
+ if a specified option is not supported by the underlying build of
+ the SQLite library.
+ */
+ public static void libConfigOp( int op ){
+ checkRcStatic(CApi.sqlite3_config(op));
+ }
+
}
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java
index 111f004db4..9b4440f190 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java
@@ -12,7 +12,7 @@
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
-import static org.sqlite.jni.capi.CApi.*;
+import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;
/**
@@ -22,10 +22,10 @@
and C via JNI.
*/
public final class SqliteException extends java.lang.RuntimeException {
- int errCode = SQLITE_ERROR;
- int xerrCode = SQLITE_ERROR;
- int errOffset = -1;
- int sysErrno = 0;
+ private int errCode = CApi.SQLITE_ERROR;
+ private int xerrCode = CApi.SQLITE_ERROR;
+ private int errOffset = -1;
+ private int sysErrno = 0;
/**
Records the given error string and uses SQLITE_ERROR for both the
@@ -38,28 +38,31 @@ public SqliteException(String msg){
/**
Uses sqlite3_errstr(sqlite3ResultCode) for the error string and
sets both the error code and extended error code to the given
- value.
+ value. This approach includes no database-level information and
+ systemErrno() will be 0, so is intended only for use with sqlite3
+ APIs for which a result code is not an error but which the
+ higher-level wrapper should treat as one.
*/
public SqliteException(int sqlite3ResultCode){
- super(sqlite3_errstr(sqlite3ResultCode));
+ super(CApi.sqlite3_errstr(sqlite3ResultCode));
errCode = xerrCode = sqlite3ResultCode;
}
/**
Records the current error state of db (which must not be null and
- must refer to an opened db object). Note that this does NOT close
+ must refer to an opened db object). Note that this does not close
the db.
- Design note: closing the db on error is likely only useful during
+ Design note: closing the db on error is really only useful during
a failed db-open operation, and the place(s) where that can
happen are inside this library, not client-level code.
*/
SqliteException(sqlite3 db){
- super(sqlite3_errmsg(db));
- errCode = sqlite3_errcode(db);
- xerrCode = sqlite3_extended_errcode(db);
- errOffset = sqlite3_error_offset(db);
- sysErrno = sqlite3_system_errno(db);
+ super(CApi.sqlite3_errmsg(db));
+ errCode = CApi.sqlite3_errcode(db);
+ xerrCode = CApi.sqlite3_extended_errcode(db);
+ errOffset = CApi.sqlite3_error_offset(db);
+ sysErrno = CApi.sqlite3_system_errno(db);
}
/**
@@ -71,7 +74,7 @@ public SqliteException(Sqlite db){
}
public SqliteException(Sqlite.Stmt stmt){
- this( stmt.db() );
+ this(stmt.getDb());
}
public int errcode(){ return errCode; }
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
index f5fd5f84e6..5ac41323cb 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java
@@ -12,14 +12,13 @@
** This file contains a set of tests for the sqlite3 JNI bindings.
*/
package org.sqlite.jni.wrapper1;
-//import static org.sqlite.jni.capi.CApi.*;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import org.sqlite.jni.capi.*;
+import org.sqlite.jni.capi.CApi;
/**
An annotation for Tester2 tests which we do not want to run in
@@ -46,7 +45,7 @@ public class Tester2 implements Runnable {
//! True to shuffle the order of the tests.
private static boolean shuffle = false;
//! True to dump the list of to-run tests to stdout.
- private static boolean listRunTests = false;
+ private static int listRunTests = 0;
//! True to squelch all out() and outln() output.
private static boolean quietMode = false;
//! Total number of runTests() calls.
@@ -125,49 +124,37 @@ public static void affirm(Boolean v){
}
- public static void execSql(Sqlite db, String[] sql){
+ public static void execSql(Sqlite db, String sql[]){
execSql(db, String.join("", sql));
}
+ /**
+ Executes all SQL statements in the given string. If throwOnError
+ is true then it will throw for any prepare/step errors, else it
+ will return the corresponding non-0 result code.
+ */
public static int execSql(Sqlite dbw, boolean throwOnError, String sql){
- final sqlite3 db = dbw.nativeHandle();
- OutputPointer.Int32 oTail = new OutputPointer.Int32();
- final byte[] sqlUtf8 = sql.getBytes(StandardCharsets.UTF_8);
- int pos = 0, n = 1;
- byte[] sqlChunk = sqlUtf8;
- int rc = 0;
- sqlite3_stmt stmt = null;
- final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
- while(pos < sqlChunk.length){
- if(pos > 0){
- sqlChunk = Arrays.copyOfRange(sqlChunk, pos,
- sqlChunk.length);
- }
- if( 0==sqlChunk.length ) break;
- rc = CApi.sqlite3_prepare_v2(db, sqlChunk, outStmt, oTail);
- if(throwOnError) affirm(0 == rc);
- else if( 0!=rc ) break;
- pos = oTail.value;
- stmt = outStmt.take();
- if( null == stmt ){
- // empty statement was parsed.
- continue;
- }
- affirm(0 != stmt.getNativePointer());
- while( CApi.SQLITE_ROW == (rc = CApi.sqlite3_step(stmt)) ){
- }
- CApi.sqlite3_finalize(stmt);
- affirm(0 == stmt.getNativePointer());
- if(0!=rc && CApi.SQLITE_ROW!=rc && CApi.SQLITE_DONE!=rc){
- break;
+ final ValueHolder rv = new ValueHolder<>(0);
+ final Sqlite.PrepareMulti pm = new Sqlite.PrepareMulti(){
+ @Override public void call(Sqlite.Stmt stmt){
+ try{
+ while( Sqlite.ROW == (rv.value = stmt.step(throwOnError)) ){}
+ }
+ finally{ stmt.finalizeStmt(); }
+ }
+ };
+ try {
+ dbw.prepareMulti(sql, pm);
+ }catch(SqliteException se){
+ if( throwOnError ){
+ throw se;
+ }else{
+ /* This error (likely) happened in the prepare() phase and we
+ need to preempt it. */
+ rv.value = se.errcode();
}
}
- CApi.sqlite3_finalize(stmt);
- if(CApi.SQLITE_ROW==rc || CApi.SQLITE_DONE==rc) rc = 0;
- if( 0!=rc && throwOnError){
- throw new SqliteException(db);
- }
- return rc;
+ return (rv.value==Sqlite.DONE) ? 0 : rv.value;
}
static void execSql(Sqlite db, String sql){
@@ -176,15 +163,7 @@ static void execSql(Sqlite db, String sql){
@SingleThreadOnly /* because it's thread-agnostic */
private void test1(){
- affirm(CApi.sqlite3_libversion_number() == CApi.SQLITE_VERSION_NUMBER);
- }
-
- /* Copy/paste/rename this to add new tests. */
- private void _testTemplate(){
- //final sqlite3 db = createNewDb();
- //sqlite3_stmt stmt = prepare(db,"SELECT 1");
- //sqlite3_finalize(stmt);
- //sqlite3_close_v2(db);
+ affirm(Sqlite.libVersionNumber() == CApi.SQLITE_VERSION_NUMBER);
}
private void nap() throws InterruptedException {
@@ -194,9 +173,9 @@ private void nap() throws InterruptedException {
}
Sqlite openDb(String name){
- final Sqlite db = Sqlite.open(name, CApi.SQLITE_OPEN_READWRITE|
- CApi.SQLITE_OPEN_CREATE|
- CApi.SQLITE_OPEN_EXRESCODE);
+ final Sqlite db = Sqlite.open(name, Sqlite.OPEN_READWRITE|
+ Sqlite.OPEN_CREATE|
+ Sqlite.OPEN_EXRESCODE);
++metrics.dbOpen;
return db;
}
@@ -206,15 +185,24 @@ Sqlite openDb(String name){
void testOpenDb1(){
Sqlite db = openDb();
affirm( 0!=db.nativeHandle().getNativePointer() );
+ affirm( "main".equals( db.dbName(0) ) );
+ db.setMainDbName("foo");
+ affirm( "foo".equals( db.dbName(0) ) );
+ affirm( db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, true)
+ /* The underlying function has different mangled names in jdk8
+ vs jdk19, and this call is here to ensure that the build
+ fails if it cannot find both names. */ );
+ affirm( !db.dbConfig(Sqlite.DBCONFIG_DEFENSIVE, false) );
+ SqliteException ex = null;
+ try{ db.dbConfig(0, false); }
+ catch(SqliteException e){ ex = e; }
+ affirm( null!=ex );
+ ex = null;
db.close();
affirm( null==db.nativeHandle() );
- SqliteException ex = null;
- try {
- db = openDb("/no/such/dir/.../probably");
- }catch(SqliteException e){
- ex = e;
- }
+ try{ db = openDb("/no/such/dir/.../probably"); }
+ catch(SqliteException e){ ex = e; }
affirm( ex!=null );
affirm( ex.errcode() != 0 );
affirm( ex.extendedErrcode() != 0 );
@@ -224,19 +212,51 @@ void testOpenDb1(){
void testPrepare1(){
try (Sqlite db = openDb()) {
- Sqlite.Stmt stmt = db.prepare("SELECT 1");
+ Sqlite.Stmt stmt = db.prepare("SELECT ?1");
+ Exception e = null;
affirm( null!=stmt.nativeHandle() );
- affirm( CApi.SQLITE_ROW == stmt.step() );
- affirm( CApi.SQLITE_DONE == stmt.step() );
+ affirm( db == stmt.getDb() );
+ affirm( 1==stmt.bindParameterCount() );
+ affirm( "?1".equals(stmt.bindParameterName(1)) );
+ affirm( null==stmt.bindParameterName(2) );
+ stmt.bindInt64(1, 1);
+ stmt.bindDouble(1, 1.1);
+ stmt.bindObject(1, db);
+ stmt.bindNull(1);
+ stmt.bindText(1, new byte[] {32,32,32});
+ stmt.bindText(1, "123");
+ stmt.bindText16(1, "123".getBytes(StandardCharsets.UTF_16));
+ stmt.bindText16(1, "123");
+ stmt.bindZeroBlob(1, 8);
+ stmt.bindBlob(1, new byte[] {1,2,3,4});
+ stmt.bindInt(1, 17);
+ try{ stmt.bindInt(2,1); }
+ catch(Exception ex){ e = ex; }
+ affirm( null!=e );
+ e = null;
+ affirm( stmt.step() );
+ try{ stmt.columnInt(1); }
+ catch(Exception ex){ e = ex; }
+ affirm( null!=e );
+ e = null;
+ affirm( 17 == stmt.columnInt(0) );
+ affirm( 17L == stmt.columnInt64(0) );
+ affirm( 17.0 == stmt.columnDouble(0) );
+ affirm( "17".equals(stmt.columnText16(0)) );
+ affirm( !stmt.step() );
stmt.reset();
- affirm( CApi.SQLITE_ROW == stmt.step() );
- affirm( CApi.SQLITE_DONE == stmt.step() );
+ affirm( Sqlite.ROW==stmt.step(false) );
+ affirm( !stmt.step() );
affirm( 0 == stmt.finalizeStmt() );
affirm( null==stmt.nativeHandle() );
- stmt = db.prepare("SELECT 1");
- affirm( CApi.SQLITE_ROW == stmt.step() );
- affirm( 0 == stmt.finalizeStmt() )
+ stmt = db.prepare("SELECT ?");
+ stmt.bindObject(1, db);
+ affirm( Sqlite.ROW == stmt.step(false) );
+ affirm( db==stmt.columnObject(0) );
+ affirm( db==stmt.columnObject(0, Sqlite.class ) );
+ affirm( null==stmt.columnObject(0, Sqlite.Stmt.class ) );
+ affirm( 0==stmt.finalizeStmt() )
/* getting a non-0 out of sqlite3_finalize() is tricky */;
affirm( null==stmt.nativeHandle() );
}
@@ -249,28 +269,37 @@ void testUdfScalar(){
final ValueHolder vh = new ValueHolder<>(0);
final ScalarFunction f = new ScalarFunction(){
public void xFunc(SqlFunction.Arguments args){
+ affirm( db == args.getDb() );
for( SqlFunction.Arguments.Arg arg : args ){
vh.value += arg.getInt();
}
+ args.resultInt(vh.value);
}
public void xDestroy(){
++xDestroyCalled.value;
}
};
db.createFunction("myfunc", -1, f);
- execSql(db, "select myfunc(1,2,3)");
+ Sqlite.Stmt q = db.prepare("select myfunc(1,2,3)");
+ affirm( q.step() );
affirm( 6 == vh.value );
+ affirm( 6 == q.columnInt(0) );
+ q.finalizeStmt();
+ affirm( 0 == xDestroyCalled.value );
vh.value = 0;
- execSql(db, "select myfunc(-1,-2,-3)");
+ q = db.prepare("select myfunc(-1,-2,-3)");
+ affirm( q.step() );
affirm( -6 == vh.value );
+ affirm( -6 == q.columnInt(0) );
affirm( 0 == xDestroyCalled.value );
+ q.finalizeStmt();
}
affirm( 1 == xDestroyCalled.value );
}
void testUdfAggregate(){
final ValueHolder xDestroyCalled = new ValueHolder<>(0);
- final ValueHolder vh = new ValueHolder<>(0);
+ Sqlite.Stmt q = null;
try (Sqlite db = openDb()) {
execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
final AggregateFunction f = new AggregateFunction(){
@@ -284,18 +313,650 @@ public void xFinal(SqlFunction.Arguments args){
final Integer v = this.takeAggregateState(args);
if( null==v ) args.resultNull();
else args.resultInt(v);
- vh.value = v;
}
public void xDestroy(){
++xDestroyCalled.value;
}
};
- db.createFunction("myagg", -1, f);
- execSql(db, "select myagg(a) from t");
- affirm( 6 == vh.value );
+ db.createFunction("summer", 1, f);
+ q = db.prepare(
+ "with cte(v) as ("+
+ "select 3 union all select 5 union all select 7"+
+ ") select summer(v), summer(v+1) from cte"
+ /* ------------------^^^^^^^^^^^ ensures that we're handling
+ sqlite3_aggregate_context() properly. */
+ );
+ affirm( q.step() );
+ affirm( 15==q.columnInt(0) );
+ q.finalizeStmt();
+ q = null;
affirm( 0 == xDestroyCalled.value );
+ db.createFunction("summerN", -1, f);
+
+ q = db.prepare("select summerN(1,8,9), summerN(2,3,4)");
+ affirm( q.step() );
+ affirm( 18==q.columnInt(0) );
+ affirm( 9==q.columnInt(1) );
+ q.finalizeStmt();
+ q = null;
+
+ }/*db*/
+ finally{
+ if( null!=q ) q.finalizeStmt();
+ }
+ affirm( 2 == xDestroyCalled.value
+ /* because we've bound the same instance twice */ );
+ }
+
+ private void testUdfWindow(){
+ final Sqlite db = openDb();
+ /* Example window function, table, and results taken from:
+ https://sqlite.org/windowfunctions.html#udfwinfunc */
+ final WindowFunction func = new WindowFunction(){
+ //! Impl of xStep() and xInverse()
+ private void xStepInverse(SqlFunction.Arguments args, int v){
+ this.getAggregateState(args,0).value += v;
+ }
+ @Override public void xStep(SqlFunction.Arguments args){
+ this.xStepInverse(args, args.getInt(0));
+ }
+ @Override public void xInverse(SqlFunction.Arguments args){
+ this.xStepInverse(args, -args.getInt(0));
+ }
+ //! Impl of xFinal() and xValue()
+ private void xFinalValue(SqlFunction.Arguments args, Integer v){
+ if(null == v) args.resultNull();
+ else args.resultInt(v);
+ }
+ @Override public void xFinal(SqlFunction.Arguments args){
+ xFinalValue(args, this.takeAggregateState(args));
+ affirm( null == this.getAggregateState(args,null).value );
+ }
+ @Override public void xValue(SqlFunction.Arguments args){
+ xFinalValue(args, this.getAggregateState(args,null).value);
+ }
+ };
+ db.createFunction("winsumint", 1, func);
+ execSql(db, new String[] {
+ "CREATE TEMP TABLE twin(x, y); INSERT INTO twin VALUES",
+ "('a', 4),('b', 5),('c', 3),('d', 8),('e', 1)"
+ });
+ final Sqlite.Stmt stmt = db.prepare(
+ "SELECT x, winsumint(y) OVER ("+
+ "ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
+ ") AS sum_y "+
+ "FROM twin ORDER BY x;"
+ );
+ int n = 0;
+ while( stmt.step() ){
+ final String s = stmt.columnText16(0);
+ final int i = stmt.columnInt(1);
+ switch(++n){
+ case 1: affirm( "a".equals(s) && 9==i ); break;
+ case 2: affirm( "b".equals(s) && 12==i ); break;
+ case 3: affirm( "c".equals(s) && 16==i ); break;
+ case 4: affirm( "d".equals(s) && 12==i ); break;
+ case 5: affirm( "e".equals(s) && 9==i ); break;
+ default: affirm( false /* cannot happen */ );
+ }
+ }
+ stmt.close();
+ affirm( 5 == n );
+ db.close();
+ }
+
+ private void testKeyword(){
+ final int n = Sqlite.keywordCount();
+ affirm( n>0 );
+ affirm( !Sqlite.keywordCheck("_nope_") );
+ affirm( Sqlite.keywordCheck("seLect") );
+ affirm( null!=Sqlite.keywordName(0) );
+ affirm( null!=Sqlite.keywordName(n-1) );
+ affirm( null==Sqlite.keywordName(n) );
+ }
+
+
+ private void testExplain(){
+ final Sqlite db = openDb();
+ Sqlite.Stmt q = db.prepare("SELECT 1");
+ affirm( 0 == q.isExplain() );
+ q.explain(0);
+ affirm( 0 == q.isExplain() );
+ q.explain(1);
+ affirm( 1 == q.isExplain() );
+ q.explain(2);
+ affirm( 2 == q.isExplain() );
+ Exception ex = null;
+ try{
+ q.explain(-1);
+ }catch(Exception e){
+ ex = e;
+ }
+ affirm( ex instanceof SqliteException );
+ q.finalizeStmt();
+ db.close();
+ }
+
+
+ private void testTrace(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ /* Ensure that characters outside of the UTF BMP survive the trip
+ from Java to sqlite3 and back to Java. (At no small efficiency
+ penalty.) */
+ final String nonBmpChar = "😃";
+ db.trace(
+ Sqlite.TRACE_ALL,
+ new Sqlite.TraceCallback(){
+ @Override public void call(int traceFlag, Object pNative, Object x){
+ ++counter.value;
+ //outln("TRACE "+traceFlag+" pNative = "+pNative.getClass().getName());
+ switch(traceFlag){
+ case Sqlite.TRACE_STMT:
+ affirm(pNative instanceof Sqlite.Stmt);
+ //outln("TRACE_STMT sql = "+x);
+ affirm(x instanceof String);
+ affirm( ((String)x).indexOf(nonBmpChar) > 0 );
+ break;
+ case Sqlite.TRACE_PROFILE:
+ affirm(pNative instanceof Sqlite.Stmt);
+ affirm(x instanceof Long);
+ //outln("TRACE_PROFILE time = "+x);
+ break;
+ case Sqlite.TRACE_ROW:
+ affirm(pNative instanceof Sqlite.Stmt);
+ affirm(null == x);
+ //outln("TRACE_ROW = "+sqlite3_column_text16((sqlite3_stmt)pNative, 0));
+ break;
+ case Sqlite.TRACE_CLOSE:
+ affirm(pNative instanceof Sqlite);
+ affirm(null == x);
+ break;
+ default:
+ affirm(false /*cannot happen*/);
+ break;
+ }
+ }
+ });
+ execSql(db, "SELECT coalesce(null,null,'"+nonBmpChar+"'); "+
+ "SELECT 'w"+nonBmpChar+"orld'");
+ affirm( 6 == counter.value );
+ db.close();
+ affirm( 7 == counter.value );
+ }
+
+ private void testStatus(){
+ final Sqlite db = openDb();
+ execSql(db, "create table t(a); insert into t values(1),(2),(3)");
+
+ Sqlite.Status s = Sqlite.libStatus(Sqlite.STATUS_MEMORY_USED, false);
+ affirm( s.current > 0 );
+ affirm( s.peak >= s.current );
+
+ s = db.status(Sqlite.DBSTATUS_SCHEMA_USED, false);
+ affirm( s.current > 0 );
+ affirm( s.peak == 0 /* always 0 for SCHEMA_USED */ );
+
+ db.close();
+ }
+
+ @SingleThreadOnly /* because multiple threads legitimately make these
+ results unpredictable */
+ private synchronized void testAutoExtension(){
+ final ValueHolder val = new ValueHolder<>(0);
+ final ValueHolder toss = new ValueHolder<>(null);
+ final Sqlite.AutoExtension ax = new Sqlite.AutoExtension(){
+ @Override public void call(Sqlite db){
+ ++val.value;
+ if( null!=toss.value ){
+ throw new RuntimeException(toss.value);
+ }
+ }
+ };
+ Sqlite.addAutoExtension(ax);
+ openDb().close();
+ affirm( 1==val.value );
+ openDb().close();
+ affirm( 2==val.value );
+ Sqlite.clearAutoExtensions();
+ openDb().close();
+ affirm( 2==val.value );
+
+ Sqlite.addAutoExtension( ax );
+ Sqlite.addAutoExtension( ax ); // Must not add a second entry
+ Sqlite.addAutoExtension( ax ); // or a third one
+ openDb().close();
+ affirm( 3==val.value );
+
+ Sqlite db = openDb();
+ affirm( 4==val.value );
+ execSql(db, "ATTACH ':memory:' as foo");
+ affirm( 4==val.value, "ATTACH uses the same connection, not sub-connections." );
+ db.close();
+ db = null;
+
+ Sqlite.removeAutoExtension(ax);
+ openDb().close();
+ affirm( 4==val.value );
+ Sqlite.addAutoExtension(ax);
+ Exception err = null;
+ toss.value = "Throwing from auto_extension.";
+ try{
+ openDb();
+ }catch(Exception e){
+ err = e;
+ }
+ affirm( err!=null );
+ affirm( err.getMessage().indexOf(toss.value)>=0 );
+ toss.value = null;
+
+ val.value = 0;
+ final Sqlite.AutoExtension ax2 = new Sqlite.AutoExtension(){
+ @Override public void call(Sqlite db){
+ ++val.value;
+ }
+ };
+ Sqlite.addAutoExtension(ax2);
+ openDb().close();
+ affirm( 2 == val.value );
+ Sqlite.removeAutoExtension(ax);
+ openDb().close();
+ affirm( 3 == val.value );
+ Sqlite.addAutoExtension(ax);
+ openDb().close();
+ affirm( 5 == val.value );
+ Sqlite.removeAutoExtension(ax2);
+ openDb().close();
+ affirm( 6 == val.value );
+ Sqlite.addAutoExtension(ax2);
+ openDb().close();
+ affirm( 8 == val.value );
+
+ Sqlite.clearAutoExtensions();
+ openDb().close();
+ affirm( 8 == val.value );
+ }
+
+ private void testBackup(){
+ final Sqlite dbDest = openDb();
+
+ try (Sqlite dbSrc = openDb()) {
+ execSql(dbSrc, new String[]{
+ "pragma page_size=512; VACUUM;",
+ "create table t(a);",
+ "insert into t(a) values(1),(2),(3);"
+ });
+ Exception e = null;
+ try {
+ dbSrc.initBackup("main",dbSrc,"main");
+ }catch(Exception x){
+ e = x;
+ }
+ affirm( e instanceof SqliteException );
+ e = null;
+ try (Sqlite.Backup b = dbDest.initBackup("main",dbSrc,"main")) {
+ affirm( null!=b );
+ int rc;
+ while( Sqlite.DONE!=(rc = b.step(1)) ){
+ affirm( 0==rc );
+ }
+ affirm( b.pageCount() > 0 );
+ b.finish();
+ }
+ }
+
+ try (Sqlite.Stmt q = dbDest.prepare("SELECT sum(a) from t")) {
+ q.step();
+ affirm( q.columnInt(0) == 6 );
+ }
+ dbDest.close();
+ }
+
+ private void testCollation(){
+ final Sqlite db = openDb();
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ final Sqlite.Collation myCollation = new Sqlite.Collation() {
+ private String myState =
+ "this is local state. There is much like it, but this is mine.";
+ @Override
+ // Reverse-sorts its inputs...
+ public int call(byte[] lhs, byte[] rhs){
+ int len = lhs.length > rhs.length ? rhs.length : lhs.length;
+ int c = 0, i = 0;
+ for(i = 0; i < len; ++i){
+ c = lhs[i] - rhs[i];
+ if(0 != c) break;
+ }
+ if(0==c){
+ if(i < lhs.length) c = 1;
+ else if(i < rhs.length) c = -1;
+ }
+ return -c;
+ }
+ };
+ final Sqlite.CollationNeeded collLoader = new Sqlite.CollationNeeded(){
+ @Override
+ public void call(Sqlite dbArg, int eTextRep, String collationName){
+ affirm(dbArg == db);
+ db.createCollation("reversi", eTextRep, myCollation);
+ }
+ };
+ db.onCollationNeeded(collLoader);
+ Sqlite.Stmt stmt = db.prepare("SELECT a FROM t ORDER BY a COLLATE reversi");
+ int counter = 0;
+ while( stmt.step() ){
+ final String val = stmt.columnText16(0);
+ ++counter;
+ switch(counter){
+ case 1: affirm("c".equals(val)); break;
+ case 2: affirm("b".equals(val)); break;
+ case 3: affirm("a".equals(val)); break;
+ }
+ }
+ affirm(3 == counter);
+ stmt.finalizeStmt();
+ stmt = db.prepare("SELECT a FROM t ORDER BY a");
+ counter = 0;
+ while( stmt.step() ){
+ final String val = stmt.columnText16(0);
+ ++counter;
+ //outln("Non-REVERSI'd row#"+counter+": "+val);
+ switch(counter){
+ case 3: affirm("c".equals(val)); break;
+ case 2: affirm("b".equals(val)); break;
+ case 1: affirm("a".equals(val)); break;
+ }
+ }
+ affirm(3 == counter);
+ stmt.finalizeStmt();
+ db.onCollationNeeded(null);
+ db.close();
+ }
+
+ @SingleThreadOnly /* because threads inherently break this test */
+ private void testBusy(){
+ final String dbName = "_busy-handler.db";
+ try{
+ Sqlite db1 = openDb(dbName);
+ ++metrics.dbOpen;
+ execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
+ Sqlite db2 = openDb(dbName);
+ ++metrics.dbOpen;
+
+ final ValueHolder xBusyCalled = new ValueHolder<>(0);
+ Sqlite.BusyHandler handler = new Sqlite.BusyHandler(){
+ @Override public int call(int n){
+ return n > 2 ? 0 : ++xBusyCalled.value;
+ }
+ };
+ db2.setBusyHandler(handler);
+
+ // Force a locked condition...
+ execSql(db1, "BEGIN EXCLUSIVE");
+ int rc = 0;
+ SqliteException ex = null;
+ try{
+ db2.prepare("SELECT * from t");
+ }catch(SqliteException x){
+ ex = x;
+ }
+ affirm( null!=ex );
+ affirm( Sqlite.BUSY == ex.errcode() );
+ affirm( 3 == xBusyCalled.value );
+ db1.close();
+ db2.close();
+ }finally{
+ try{(new java.io.File(dbName)).delete();}
+ catch(Exception e){/* ignore */}
+ }
+ }
+
+ private void testCommitHook(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ final ValueHolder hookResult = new ValueHolder<>(0);
+ final Sqlite.CommitHook theHook = new Sqlite.CommitHook(){
+ @Override public int call(){
+ ++counter.value;
+ return hookResult.value;
+ }
+ };
+ Sqlite.CommitHook oldHook = db.setCommitHook(theHook);
+ affirm( null == oldHook );
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ affirm( 2 == counter.value );
+ execSql(db, "BEGIN; SELECT 1; SELECT 2; COMMIT;");
+ affirm( 2 == counter.value /* NOT invoked if no changes are made */ );
+ execSql(db, "BEGIN; update t set a='d' where a='c'; COMMIT;");
+ affirm( 3 == counter.value );
+ oldHook = db.setCommitHook(theHook);
+ affirm( theHook == oldHook );
+ execSql(db, "BEGIN; update t set a='e' where a='d'; COMMIT;");
+ affirm( 4 == counter.value );
+ oldHook = db.setCommitHook(null);
+ affirm( theHook == oldHook );
+ execSql(db, "BEGIN; update t set a='f' where a='e'; COMMIT;");
+ affirm( 4 == counter.value );
+ oldHook = db.setCommitHook(null);
+ affirm( null == oldHook );
+ execSql(db, "BEGIN; update t set a='g' where a='f'; COMMIT;");
+ affirm( 4 == counter.value );
+
+ final Sqlite.CommitHook newHook = new Sqlite.CommitHook(){
+ @Override public int call(){return 0;}
+ };
+ oldHook = db.setCommitHook(newHook);
+ affirm( null == oldHook );
+ execSql(db, "BEGIN; update t set a='h' where a='g'; COMMIT;");
+ affirm( 4 == counter.value );
+ oldHook = db.setCommitHook(theHook);
+ affirm( newHook == oldHook );
+ execSql(db, "BEGIN; update t set a='i' where a='h'; COMMIT;");
+ affirm( 5 == counter.value );
+ hookResult.value = Sqlite.ERROR;
+ int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
+ affirm( Sqlite.CONSTRAINT_COMMITHOOK == rc );
+ affirm( 6 == counter.value );
+ db.close();
+ }
+
+ private void testRollbackHook(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ final Sqlite.RollbackHook theHook = new Sqlite.RollbackHook(){
+ @Override public void call(){
+ ++counter.value;
+ }
+ };
+ Sqlite.RollbackHook oldHook = db.setRollbackHook(theHook);
+ affirm( null == oldHook );
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ affirm( 0 == counter.value );
+ execSql(db, false, "BEGIN; SELECT 1; SELECT 2; ROLLBACK;");
+ affirm( 1 == counter.value /* contra to commit hook, is invoked if no changes are made */ );
+
+ final Sqlite.RollbackHook newHook = new Sqlite.RollbackHook(){
+ @Override public void call(){}
+ };
+ oldHook = db.setRollbackHook(newHook);
+ affirm( theHook == oldHook );
+ execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+ affirm( 1 == counter.value );
+ oldHook = db.setRollbackHook(theHook);
+ affirm( newHook == oldHook );
+ execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+ affirm( 2 == counter.value );
+ int rc = execSql(db, false, "BEGIN; SELECT 1; ROLLBACK;");
+ affirm( 0 == rc );
+ affirm( 3 == counter.value );
+ db.close();
+ }
+
+ private void testUpdateHook(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ final ValueHolder expectedOp = new ValueHolder<>(0);
+ final Sqlite.UpdateHook theHook = new Sqlite.UpdateHook(){
+ @Override
+ public void call(int opId, String dbName, String tableName, long rowId){
+ ++counter.value;
+ if( 0!=expectedOp.value ){
+ affirm( expectedOp.value == opId );
+ }
+ }
+ };
+ Sqlite.UpdateHook oldHook = db.setUpdateHook(theHook);
+ affirm( null == oldHook );
+ expectedOp.value = Sqlite.INSERT;
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ affirm( 3 == counter.value );
+ expectedOp.value = Sqlite.UPDATE;
+ execSql(db, "update t set a='d' where a='c';");
+ affirm( 4 == counter.value );
+ oldHook = db.setUpdateHook(theHook);
+ affirm( theHook == oldHook );
+ expectedOp.value = Sqlite.DELETE;
+ execSql(db, "DELETE FROM t where a='d'");
+ affirm( 5 == counter.value );
+ oldHook = db.setUpdateHook(null);
+ affirm( theHook == oldHook );
+ execSql(db, "update t set a='e' where a='b';");
+ affirm( 5 == counter.value );
+ oldHook = db.setUpdateHook(null);
+ affirm( null == oldHook );
+
+ final Sqlite.UpdateHook newHook = new Sqlite.UpdateHook(){
+ @Override public void call(int opId, String dbName, String tableName, long rowId){
+ }
+ };
+ oldHook = db.setUpdateHook(newHook);
+ affirm( null == oldHook );
+ execSql(db, "update t set a='h' where a='a'");
+ affirm( 5 == counter.value );
+ oldHook = db.setUpdateHook(theHook);
+ affirm( newHook == oldHook );
+ expectedOp.value = Sqlite.UPDATE;
+ execSql(db, "update t set a='i' where a='h'");
+ affirm( 6 == counter.value );
+ db.close();
+ }
+
+ private void testProgress(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ db.setProgressHandler(1, new Sqlite.ProgressHandler(){
+ @Override public int call(){
+ ++counter.value;
+ return 0;
+ }
+ });
+ execSql(db, "SELECT 1; SELECT 2;");
+ affirm( counter.value > 0 );
+ int nOld = counter.value;
+ db.setProgressHandler(0, null);
+ execSql(db, "SELECT 1; SELECT 2;");
+ affirm( nOld == counter.value );
+ db.close();
+ }
+
+ private void testAuthorizer(){
+ final Sqlite db = openDb();
+ final ValueHolder counter = new ValueHolder<>(0);
+ final ValueHolder authRc = new ValueHolder<>(0);
+ final Sqlite.Authorizer auth = new Sqlite.Authorizer(){
+ public int call(int op, String s0, String s1, String s2, String s3){
+ ++counter.value;
+ //outln("xAuth(): "+s0+" "+s1+" "+s2+" "+s3);
+ return authRc.value;
+ }
+ };
+ execSql(db, "CREATE TABLE t(a); INSERT INTO t(a) VALUES('a'),('b'),('c')");
+ db.setAuthorizer(auth);
+ execSql(db, "UPDATE t SET a=1");
+ affirm( 1 == counter.value );
+ authRc.value = Sqlite.DENY;
+ int rc = execSql(db, false, "UPDATE t SET a=2");
+ affirm( Sqlite.AUTH==rc );
+ db.setAuthorizer(null);
+ rc = execSql(db, false, "UPDATE t SET a=2");
+ affirm( 0==rc );
+ db.close();
+ }
+
+ private void testBlobOpen(){
+ final Sqlite db = openDb();
+
+ execSql(db, "CREATE TABLE T(a BLOB);"
+ +"INSERT INTO t(rowid,a) VALUES(1, 'def'),(2, 'XYZ');"
+ );
+ Sqlite.Blob b = db.blobOpen("main", "t", "a",
+ db.lastInsertRowId(), true);
+ affirm( 3==b.bytes() );
+ b.write(new byte[] {100, 101, 102 /*"DEF"*/}, 0);
+ b.close();
+ Sqlite.Stmt stmt = db.prepare("SELECT length(a), a FROM t ORDER BY a");
+ affirm( stmt.step() );
+ affirm( 3 == stmt.columnInt(0) );
+ affirm( "def".equals(stmt.columnText16(1)) );
+ stmt.finalizeStmt();
+
+ b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), false);
+ final byte[] tgt = new byte[3];
+ b.read( tgt, 0 );
+ affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
+ execSql(db,"UPDATE t SET a=zeroblob(10) WHERE rowid=2");
+ b.close();
+ b = db.blobOpen("main", "t", "a", db.lastInsertRowId(), true);
+ byte[] bw = new byte[]{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+ };
+ b.write(bw, 0);
+ byte[] br = new byte[10];
+ b.read(br, 0);
+ for( int i = 0; i < br.length; ++i ){
+ affirm(bw[i] == br[i]);
+ }
+ b.close();
+ db.close();
+ }
+
+ void testPrepareMulti(){
+ final ValueHolder fCount = new ValueHolder<>(0);
+ final ValueHolder mCount = new ValueHolder<>(0);
+ try (Sqlite db = openDb()) {
+ execSql(db, "create table t(a); insert into t(a) values(1),(2),(3)");
+ db.createFunction("counter", -1, new ScalarFunction(){
+ @Override public void xFunc(SqlFunction.Arguments args){
+ ++fCount.value;
+ args.resultNull();
+ }
+ }
+ );
+ final Sqlite.PrepareMulti pm = new Sqlite.PrepareMultiFinalize(
+ new Sqlite.PrepareMulti() {
+ @Override public void call(Sqlite.Stmt q){
+ ++mCount.value;
+ while(q.step()){}
+ }
+ }
+ );
+ final String sql = "select counter(*) from t;"+
+ "select counter(*) from t; /* comment */"+
+ "select counter(*) from t; -- comment\n"
+ ;
+ db.prepareMulti(sql, pm);
+ }
+ affirm( 3 == mCount.value );
+ affirm( 9 == fCount.value );
+ }
+
+
+ /* Copy/paste/rename this to add new tests. */
+ private void _testTemplate(){
+ try (Sqlite db = openDb()) {
+ Sqlite.Stmt stmt = db.prepare("SELECT 1");
+ stmt.finalizeStmt();
}
- affirm( 1 == xDestroyCalled.value );
}
private void runTests(boolean fromThread) throws Exception {
@@ -305,7 +966,7 @@ private void runTests(boolean fromThread) throws Exception {
mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
java.util.Collections.shuffle(mlist);
}
- if( listRunTests ){
+ if( (!fromThread && listRunTests>0) || listRunTests>1 ){
synchronized(this.getClass()){
if( !fromThread ){
out("Initial test"," list: ");
@@ -344,8 +1005,7 @@ public void run() {
listErrors.add(e);
}
}finally{
- affirm( CApi.sqlite3_java_uncache_thread() );
- affirm( !CApi.sqlite3_java_uncache_thread() );
+ Sqlite.uncacheThread();
}
}
@@ -368,7 +1028,9 @@ public void run() {
some chaos for cross-thread contention.
-list-tests: outputs the list of tests being run, minus some
- which are hard-coded. This is noisy in multi-threaded mode.
+ which are hard-coded. In multi-threaded mode, use this twice to
+ to emit the list run by each thread (which may differ from the initial
+ list, in particular if -shuffle is used).
-fail: forces an exception to be thrown during the test run. Use
with -shuffle to make its appearance unpredictable.
@@ -397,7 +1059,7 @@ public static void main(String[] args) throws Exception {
}else if(arg.equals("shuffle")){
shuffle = true;
}else if(arg.equals("list-tests")){
- listRunTests = true;
+ ++listRunTests;
}else if(arg.equals("fail")){
forceFail = true;
}else if(arg.equals("sqllog")){
@@ -415,39 +1077,29 @@ public static void main(String[] args) throws Exception {
}
if( sqlLog ){
- if( CApi.sqlite3_compileoption_used("ENABLE_SQLLOG") ){
- final ConfigSqllogCallback log = new ConfigSqllogCallback() {
- @Override public void call(sqlite3 db, String msg, int op){
+ if( Sqlite.compileOptionUsed("ENABLE_SQLLOG") ){
+ Sqlite.libConfigSqlLog( new Sqlite.ConfigSqlLog() {
+ @Override public void call(Sqlite db, String msg, int op){
switch(op){
case 0: outln("Opening db: ",db); break;
case 1: outln("SQL ",db,": ",msg); break;
case 2: outln("Closing db: ",db); break;
}
}
- };
- int rc = CApi.sqlite3_config( log );
- affirm( 0==rc );
- rc = CApi.sqlite3_config( (ConfigSqllogCallback)null );
- affirm( 0==rc );
- rc = CApi.sqlite3_config( log );
- affirm( 0==rc );
+ }
+ );
}else{
outln("WARNING: -sqllog is not active because library was built ",
"without SQLITE_ENABLE_SQLLOG.");
}
}
if( configLog ){
- final ConfigLogCallback log = new ConfigLogCallback() {
+ Sqlite.libConfigLog( new Sqlite.ConfigLog() {
@Override public void call(int code, String msg){
- outln("ConfigLogCallback: ",ResultCode.getEntryForInt(code),": ", msg);
+ outln("ConfigLog: ",Sqlite.errstr(code),": ", msg);
};
- };
- int rc = CApi.sqlite3_config( log );
- affirm( 0==rc );
- rc = CApi.sqlite3_config( (ConfigLogCallback)null );
- affirm( 0==rc );
- rc = CApi.sqlite3_config( log );
- affirm( 0==rc );
+ }
+ );
}
quietMode = squelchTestOutput;
@@ -480,39 +1132,16 @@ public static void main(String[] args) throws Exception {
}
final long timeStart = System.currentTimeMillis();
- int nLoop = 0;
- switch( CApi.sqlite3_threadsafe() ){ /* Sanity checking */
- case 0:
- affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
- "Could not switch to single-thread mode." );
- affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
- "Could switch to multithread mode." );
- affirm( CApi.SQLITE_ERROR==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
- "Could not switch to serialized threading mode." );
- outln("This is a single-threaded build. Not using threads.");
- nThread = 1;
- break;
- case 1:
- case 2:
- affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SINGLETHREAD ),
- "Could not switch to single-thread mode." );
- affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_MULTITHREAD ),
- "Could not switch to multithread mode." );
- affirm( 0==CApi.sqlite3_config( CApi.SQLITE_CONFIG_SERIALIZED ),
- "Could not switch to serialized threading mode." );
- break;
- default:
- affirm( false, "Unhandled SQLITE_THREADSAFE value." );
- }
outln("libversion_number: ",
- CApi.sqlite3_libversion_number(),"\n",
- CApi.sqlite3_libversion(),"\n",CApi.SQLITE_SOURCE_ID,"\n",
+ Sqlite.libVersionNumber(),"\n",
+ Sqlite.libVersion(),"\n",Sqlite.libSourceId(),"\n",
"SQLITE_THREADSAFE=",CApi.sqlite3_threadsafe());
final boolean showLoopCount = (nRepeat>1 && nThread>1);
if( showLoopCount ){
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
}
if( takeNaps ) outln("Napping between tests is enabled.");
+ int nLoop = 0;
for( int n = 0; n < nRepeat; ++n ){
++nLoop;
if( showLoopCount ) out((1==nLoop ? "" : " ")+nLoop);
@@ -554,7 +1183,7 @@ public static void main(String[] args) throws Exception {
if( doSomethingForDev ){
CApi.sqlite3_jni_internal_details();
}
- affirm( 0==CApi.sqlite3_release_memory(1) );
+ affirm( 0==Sqlite.libReleaseMemory(1) );
CApi.sqlite3_shutdown();
int nMethods = 0;
int nNatives = 0;
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java b/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java
index 009936a43e..7549bb97b2 100644
--- a/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java
@@ -9,13 +9,13 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** This file contains a set of tests for the sqlite3 JNI bindings.
+** This file contains the ValueHolder utility class.
*/
package org.sqlite.jni.wrapper1;
/**
A helper class which simply holds a single value. Its primary use
- is for communicating values out of anonymous classes, as doing so
+ is for communicating values out of anonymous callbacks, as doing so
requires a "final" reference.
*/
public class ValueHolder {
diff --git a/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java b/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java
new file mode 100644
index 0000000000..a3905567d4
--- /dev/null
+++ b/ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java
@@ -0,0 +1,42 @@
+/*
+** 2023-10-16
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** This file is part of the wrapper1 interface for sqlite3.
+*/
+package org.sqlite.jni.wrapper1;
+
+/**
+ A SqlFunction implementation for window functions. The T type
+ represents the type of data accumulated by this function while it
+ works. e.g. a SUM()-like UDF might use Integer or Long and a
+ CONCAT()-like UDF might use a StringBuilder or a List.
+*/
+public abstract class WindowFunction extends AggregateFunction {
+
+ /**
+ As for the xInverse() argument of the C API's
+ sqlite3_create_window_function(). If this function throws, the
+ exception is reported via sqlite3_result_error().
+ */
+ public abstract void xInverse(SqlFunction.Arguments args);
+
+ /**
+ As for the xValue() argument of the C API's
+ sqlite3_create_window_function(). If this function throws, it is
+ translated into sqlite3_result_error().
+
+ Note that the passed-in object will not actually contain any
+ arguments for xValue() but will contain the context object needed
+ for setting the call's result or error state.
+ */
+ public abstract void xValue(SqlFunction.Arguments args);
+
+}
diff --git a/ext/lsm1/Makefile b/ext/lsm1/Makefile
index 7056432d2d..d497a1d133 100644
--- a/ext/lsm1/Makefile
+++ b/ext/lsm1/Makefile
@@ -46,11 +46,11 @@ LSMTESTSRC = $(LSMDIR)/lsm-test/lsmtest1.c $(LSMDIR)/lsm-test/lsmtest2.c \
LSMOPTS += -fPIC -DLSM_MUTEX_PTHREADS=1 -I$(LSMDIR) -DHAVE_ZLIB
lsm.so: $(LSMOBJ)
- $(TCCX) -shared -fPIC -o lsm.so $(LSMOBJ)
+ $(T.link) -shared -fPIC -o lsm.so $(LSMOBJ)
%.o: $(LSMDIR)/%.c $(LSMHDR) sqlite3.h
- $(TCCX) $(LSMOPTS) -c $<
-
+ $(T.link) $(LSMOPTS) -c $<
+
lsmtest$(EXE): $(LSMOBJ) $(LSMTESTSRC) $(LSMTESTHDR) sqlite3.o
- # $(TCPPX) -c $(TOP)/lsm-test/lsmtest_tdb2.cc
- $(TCCX) $(LSMOPTS) $(LSMTESTSRC) $(LSMOBJ) sqlite3.o -o lsmtest$(EXE) $(THREADLIB) -lz
+ # $(T.link) -c $(TOP)/lsm-test/lsmtest_tdb2.cc
+ $(T.link) $(LSMOPTS) $(LSMTESTSRC) $(LSMOBJ) sqlite3.o -o lsmtest$(EXE) $(THREADLIB) -lz
diff --git a/ext/misc/base64.c b/ext/misc/base64.c
index bc7a976abc..17b3bbfc71 100644
--- a/ext/misc/base64.c
+++ b/ext/misc/base64.c
@@ -175,15 +175,15 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
case ND:
/* Treat dark non-digits as pad, but they terminate decode too. */
ncIn = 0;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case WS:
/* Treat whitespace as pad and terminate this group.*/
nti = nac;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
case PC:
bdp = 0;
--nbo;
- deliberate_fall_through;
+ deliberate_fall_through; /* FALLTHRU */
default: /* bdp is the digit value. */
qv = qv<<6 | bdp;
break;
@@ -192,10 +192,13 @@ static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 3:
pOut[2] = (qv) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 2:
pOut[1] = (qv>>8) & 0xff;
+ deliberate_fall_through; /* FALLTHRU */
case 1:
pOut[0] = (qv>>16) & 0xff;
+ break;
}
pOut += nbo;
}
diff --git a/ext/misc/base85.c b/ext/misc/base85.c
index e7ef0a04c9..eaf1732c46 100644
--- a/ext/misc/base85.c
+++ b/ext/misc/base85.c
@@ -232,12 +232,16 @@ static u8* fromBase85( char *pIn, int ncIn, u8 *pOut ){
switch( nbo ){
case 4:
*pOut++ = (qv >> 24)&0xff;
+ /* FALLTHRU */
case 3:
*pOut++ = (qv >> 16)&0xff;
+ /* FALLTHRU */
case 2:
*pOut++ = (qv >> 8)&0xff;
+ /* FALLTHRU */
case 1:
*pOut++ = qv&0xff;
+ /* FALLTHRU */
case 0:
break;
}
diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c
index e7c2c9d5c0..2d7f6584ea 100644
--- a/ext/misc/cksumvfs.c
+++ b/ext/misc/cksumvfs.c
@@ -446,9 +446,9 @@ static int cksmRead(
** (2) checksum verification is enabled
** (3) we are not in the middle of checkpoint
*/
- if( iAmt>=512 /* (1) */
- && p->verifyCksm /* (2) */
- && !p->inCkpt /* (3) */
+ if( iAmt>=512 && (iAmt & (iAmt-1))==0 /* (1) */
+ && p->verifyCksm /* (2) */
+ && !p->inCkpt /* (3) */
){
u8 cksum[8];
cksmCompute((u8*)zBuf, iAmt-8, cksum);
diff --git a/ext/misc/closure.c b/ext/misc/closure.c
index 79a5a21d1e..267ae1c424 100644
--- a/ext/misc/closure.c
+++ b/ext/misc/closure.c
@@ -588,12 +588,17 @@ static int closureOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
return SQLITE_OK;
}
+/*
+** Wrapper around sqlite3_free
+*/
+static void closureMemFree(closure_avl *p){ sqlite3_free(p); }
+
/*
** Free up all the memory allocated by a cursor. Set it rLimit to 0
** to indicate that it is at EOF.
*/
static void closureClearCursor(closure_cursor *pCur){
- closureAvlDestroy(pCur->pClosure, (void(*)(closure_avl*))sqlite3_free);
+ closureAvlDestroy(pCur->pClosure, closureMemFree);
sqlite3_free(pCur->zTableName);
sqlite3_free(pCur->zIdColumn);
sqlite3_free(pCur->zParentColumn);
diff --git a/ext/misc/completion.c b/ext/misc/completion.c
index 987595a3d6..54abc0ae15 100644
--- a/ext/misc/completion.c
+++ b/ext/misc/completion.c
@@ -251,7 +251,7 @@ static int completionNext(sqlite3_vtab_cursor *cur){
zSql = sqlite3_mprintf(
"%z%s"
"SELECT pti.name FROM \"%w\".sqlite_schema AS sm"
- " JOIN pragma_table_info(sm.name,%Q) AS pti"
+ " JOIN pragma_table_xinfo(sm.name,%Q) AS pti"
" WHERE sm.type='table'",
zSql, zSep, zDb, zDb
);
diff --git a/ext/misc/compress.c b/ext/misc/compress.c
index 2e7a31636d..6b034eb45f 100644
--- a/ext/misc/compress.c
+++ b/ext/misc/compress.c
@@ -89,7 +89,7 @@ static void uncompressFunc(
unsigned int nIn;
unsigned long int nOut;
int rc;
- int i;
+ unsigned int i;
pIn = sqlite3_value_blob(argv[0]);
nIn = sqlite3_value_bytes(argv[0]);
diff --git a/ext/misc/fileio.c b/ext/misc/fileio.c
index 70546adfca..80ac3b3e7c 100644
--- a/ext/misc/fileio.c
+++ b/ext/misc/fileio.c
@@ -40,7 +40,7 @@
** modification-time of the target file is set to this value before
** returning.
**
-** If three or more arguments are passed to this function and an
+** If five or more arguments are passed to this function and an
** error is encountered, an exception is raised.
**
** READFILE(FILE):
@@ -110,6 +110,13 @@ SQLITE_EXTENSION_INIT1
#include
#include
+/* When used as part of the CLI, the sqlite3_stdio.h module will have
+** been included before this one. In that case use the sqlite3_stdio.h
+** #defines. If not, create our own for fopen().
+*/
+#ifndef _SQLITE3_STDIO_H_
+# define sqlite3_fopen fopen
+#endif
/*
** Structure of the fsdir() table-valued function
@@ -142,7 +149,7 @@ static void readFileContents(sqlite3_context *ctx, const char *zName){
sqlite3 *db;
int mxBlob;
- in = fopen(zName, "rb");
+ in = sqlite3_fopen(zName, "rb");
if( in==0 ){
/* File does not exist or is unreadable. Leave the result set to NULL. */
return;
@@ -372,7 +379,9 @@ static int writeFile(
#if !defined(_WIN32) && !defined(WIN32)
if( S_ISLNK(mode) ){
const char *zTo = (const char*)sqlite3_value_text(pData);
- if( zTo==0 || symlink(zTo, zFile)<0 ) return 1;
+ if( zTo==0 ) return 1;
+ unlink(zFile);
+ if( symlink(zTo, zFile)<0 ) return 1;
}else
#endif
{
@@ -395,7 +404,7 @@ static int writeFile(
sqlite3_int64 nWrite = 0;
const char *z;
int rc = 0;
- FILE *out = fopen(zFile, "wb");
+ FILE *out = sqlite3_fopen(zFile, "wb");
if( out==0 ) return 1;
z = (const char*)sqlite3_value_blob(pData);
if( z ){
@@ -428,7 +437,7 @@ static int writeFile(
GetSystemTime(¤tTime);
SystemTimeToFileTime(¤tTime, &lastAccess);
- intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
+ intervals = (mtime*10000000) + 116444736000000000;
lastWrite.dwLowDateTime = (DWORD)intervals;
lastWrite.dwHighDateTime = intervals >> 32;
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
@@ -458,13 +467,19 @@ static int writeFile(
return 1;
}
#else
- /* Legacy unix */
- struct timeval times[2];
- times[0].tv_usec = times[1].tv_usec = 0;
- times[0].tv_sec = time(0);
- times[1].tv_sec = mtime;
- if( utimes(zFile, times) ){
- return 1;
+ /* Legacy unix.
+ **
+ ** Do not use utimes() on a symbolic link - it sees through the link and
+ ** modifies the timestamps on the target. Or fails if the target does
+ ** not exist. */
+ if( 0==S_ISLNK(mode) ){
+ struct timeval times[2];
+ times[0].tv_usec = times[1].tv_usec = 0;
+ times[0].tv_sec = time(0);
+ times[1].tv_sec = mtime;
+ if( utimes(zFile, times) ){
+ return 1;
+ }
}
#endif
}
diff --git a/ext/misc/noop.c b/ext/misc/noop.c
index d3a58670c4..18c25e10f7 100644
--- a/ext/misc/noop.c
+++ b/ext/misc/noop.c
@@ -38,6 +38,24 @@ static void noopfunc(
sqlite3_result_value(context, argv[0]);
}
+/*
+** Implementation of the multitype_text() function.
+**
+** The function returns its argument. The result will always have a
+** TEXT value. But if the original input is numeric, it will also
+** have that numeric value.
+*/
+static void multitypeTextFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ (void)argc;
+ (void)sqlite3_value_text(argv[0]);
+ sqlite3_result_value(context, argv[0]);
+}
+
#ifdef _WIN32
__declspec(dllexport)
#endif
@@ -64,5 +82,9 @@ int sqlite3_noop_init(
rc = sqlite3_create_function(db, "noop_nd", 1,
SQLITE_UTF8,
0, noopfunc, 0, 0);
+ if( rc ) return rc;
+ rc = sqlite3_create_function(db, "multitype_text", 1,
+ SQLITE_UTF8,
+ 0, multitypeTextFunc, 0, 0);
return rc;
}
diff --git a/ext/misc/percentile.c b/ext/misc/percentile.c
index d83bc5b838..06865185df 100644
--- a/ext/misc/percentile.c
+++ b/ext/misc/percentile.c
@@ -11,7 +11,7 @@
******************************************************************************
**
** This file contains code to implement the percentile(Y,P) SQL function
-** as described below:
+** and similar as described below:
**
** (1) The percentile(Y,P) function is an aggregate function taking
** exactly two arguments.
@@ -57,29 +57,108 @@
** (12) The percentile(Y,P) is implemented as a single C99 source-code
** file that compiles into a shared-library or DLL that can be loaded
** into SQLite using the sqlite3_load_extension() interface.
+**
+** (13) A separate median(Y) function is the equivalent percentile(Y,50).
+**
+** (14) A separate percentile_cont(Y,P) function is equivalent to
+** percentile(Y,P/100.0). In other words, the fraction value in
+** the second argument is in the range of 0 to 1 instead of 0 to 100.
+**
+** (15) A separate percentile_disc(Y,P) function is like
+** percentile_cont(Y,P) except that instead of returning the weighted
+** average of the nearest two input values, it returns the next lower
+** value. So the percentile_disc(Y,P) will always return a value
+** that was one of the inputs.
+**
+** (16) All of median(), percentile(Y,P), percentile_cont(Y,P) and
+** percentile_disc(Y,P) can be used as window functions.
+**
+** Differences from standard SQL:
+**
+** * The percentile_cont(X,P) function is equivalent to the following in
+** standard SQL:
+**
+** (percentile_cont(P) WITHIN GROUP (ORDER BY X))
+**
+** The SQLite syntax is much more compact. The standard SQL syntax
+** is also supported if SQLite is compiled with the
+** -DSQLITE_ENABLE_ORDERED_SET_AGGREGATES option.
+**
+** * No median(X) function exists in the SQL standard. App developers
+** are expected to write "percentile_cont(0.5)WITHIN GROUP(ORDER BY X)".
+**
+** * No percentile(Y,P) function exists in the SQL standard. Instead of
+** percential(Y,P), developers must write this:
+** "percentile_cont(P/100.0) WITHIN GROUP (ORDER BY Y)". Note that
+** the fraction parameter to percentile() goes from 0 to 100 whereas
+** the fraction parameter in SQL standard percentile_cont() goes from
+** 0 to 1.
+**
+** Implementation notes as of 2024-08-31:
+**
+** * The regular aggregate-function versions of these routines work
+** by accumulating all values in an array of doubles, then sorting
+** that array using quicksort before computing the answer. Thus
+** the runtime is O(NlogN) where N is the number of rows of input.
+**
+** * For the window-function versions of these routines, the array of
+** inputs is sorted as soon as the first value is computed. Thereafter,
+** the array is kept in sorted order using an insert-sort. This
+** results in O(N*K) performance where K is the size of the window.
+** One can imagine alternative implementations that give O(N*logN*logK)
+** performance, but they require more complex logic and data structures.
+** The developers have elected to keep the asymptotically slower
+** algorithm for now, for simplicity, under the theory that window
+** functions are seldom used and when they are, the window size K is
+** often small. The developers might revisit that decision later,
+** should the need arise.
*/
-#include "sqlite3ext.h"
-SQLITE_EXTENSION_INIT1
+#if defined(SQLITE3_H)
+ /* no-op */
+#elif defined(SQLITE_STATIC_PERCENTILE)
+# include "sqlite3.h"
+#else
+# include "sqlite3ext.h"
+ SQLITE_EXTENSION_INIT1
+#endif
#include
#include
#include
-/* The following object is the session context for a single percentile()
-** function. We have to remember all input Y values until the very end.
+/* The following object is the group context for a single percentile()
+** aggregate. Remember all input Y values until the very end.
** Those values are accumulated in the Percentile.a[] array.
*/
typedef struct Percentile Percentile;
struct Percentile {
unsigned nAlloc; /* Number of slots allocated for a[] */
unsigned nUsed; /* Number of slots actually used in a[] */
- double rPct; /* 1.0 more than the value for P */
+ char bSorted; /* True if a[] is already in sorted order */
+ char bKeepSorted; /* True if advantageous to keep a[] sorted */
+ char bPctValid; /* True if rPct is valid */
+ double rPct; /* Fraction. 0.0 to 1.0 */
double *a; /* Array of Y values */
};
+/* Details of each function in the percentile family */
+typedef struct PercentileFunc PercentileFunc;
+struct PercentileFunc {
+ const char *zName; /* Function name */
+ char nArg; /* Number of arguments */
+ char mxFrac; /* Maximum value of the "fraction" input */
+ char bDiscrete; /* True for percentile_disc() */
+};
+static const PercentileFunc aPercentFunc[] = {
+ { "median", 1, 1, 0 },
+ { "percentile", 2, 100, 0 },
+ { "percentile_cont", 2, 1, 0 },
+ { "percentile_disc", 2, 1, 1 },
+};
+
/*
** Return TRUE if the input floating-point number is an infinity.
*/
-static int isInfinity(double r){
+static int percentIsInfinity(double r){
sqlite3_uint64 u;
assert( sizeof(u)==sizeof(r) );
memcpy(&u, &r, sizeof(u));
@@ -87,13 +166,64 @@ static int isInfinity(double r){
}
/*
-** Return TRUE if two doubles differ by 0.001 or less
+** Return TRUE if two doubles differ by 0.001 or less.
*/
-static int sameValue(double a, double b){
+static int percentSameValue(double a, double b){
a -= b;
return a>=-0.001 && a<=0.001;
}
+/*
+** Search p (which must have p->bSorted) looking for an entry with
+** value y. Return the index of that entry.
+**
+** If bExact is true, return -1 if the entry is not found.
+**
+** If bExact is false, return the index at which a new entry with
+** value y should be insert in order to keep the values in sorted
+** order. The smallest return value in this case will be 0, and
+** the largest return value will be p->nUsed.
+*/
+static int percentBinarySearch(Percentile *p, double y, int bExact){
+ int iFirst = 0; /* First element of search range */
+ int iLast = p->nUsed - 1; /* Last element of search range */
+ while( iLast>=iFirst ){
+ int iMid = (iFirst+iLast)/2;
+ double x = p->a[iMid];
+ if( x