1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

sqlite3: Vendor import of sqlite3 3.53.1

Release notes at https://www.sqlite.org/releaselog/3_53_1.html.

Obtained from:  https://www.sqlite.org/2026/sqlite-autoconf-3530100.tar.gz
This commit is contained in:
Cy Schubert
2026-05-25 10:05:16 -07:00
parent e7e917ee3c
commit b00eb376e3
25 changed files with 22595 additions and 11838 deletions
+7 -4
View File
@@ -222,9 +222,12 @@ 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).
#
# Maintenance reminder: placement of $(LDFLAGS) is more relevant for
# some platforms than others:
# https://sqlite.org/forum/forumpost/d80ecdaddd
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) $(LDFLAGS.math)
sqlite3-shell-link-flags.1 = $(TOP)/sqlite3.c $(LDFLAGS) $(LDFLAGS.libsqlite3)
sqlite3-shell-link-flags.0 = $(LDFLAGS) -L. -lsqlite3 $(LDFLAGS.zlib) $(LDFLAGS.math)
sqlite3-shell-deps.1 = $(TOP)/sqlite3.c
sqlite3-shell-deps.0 = $(libsqlite3.DLL)
#
@@ -245,7 +248,7 @@ sqlite3$(T.exe): $(TOP)/shell.c $(sqlite3-shell-deps.$(ENABLE_STATIC_SHELL))
$(sqlite3-shell-static.flags.$(STATIC_CLI_SHELL)) \
-I. $(OPT_FEATURE_FLAGS) $(SHELL_OPT) \
$(CFLAGS) $(CFLAGS.readline) $(CFLAGS.icu) \
$(LDFLAGS) $(LDFLAGS.readline)
$(LDFLAGS.readline)
sqlite3$(T.exe)-1:
sqlite3$(T.exe)-0: sqlite3$(T.exe)
@@ -279,7 +282,7 @@ DIST_FILES := \
README.txt VERSION \
auto.def autosetup configure tea \
sqlite3.h sqlite3.c shell.c sqlite3ext.h \
Makefile.in Makefile.msc Makefile.fallback \
Makefile.in Makefile.msc Makefile.fallback make.bat \
sqlite3.rc sqlite3rc.h Replace.cs \
sqlite3.pc.in sqlite3.1
+17 -90
View File
@@ -101,13 +101,6 @@ NO_WARN = $(NO_WARN) -wd4210 -wd4232 -wd4244 -wd4305 -wd4306 -wd4702 -wd4706
!ENDIF
!ENDIF
# Set this non-0 to use the library paths and other options necessary for
# Windows Phone 8.1.
#
!IFNDEF USE_WP81_OPTS
USE_WP81_OPTS = 0
!ENDIF
# Set this non-0 to split the SQLite amalgamation file into chunks to
# be used for debugging with Visual Studio.
#
@@ -156,14 +149,6 @@ USE_NATIVE_LIBPATHS = 0
USE_RC = 1
!ENDIF
# Set this non-0 to compile binaries suitable for the WinRT environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
#
!IFNDEF FOR_WINRT
FOR_WINRT = 0
!ENDIF
# Set this non-0 to compile binaries suitable for the UWP environment.
# This setting does not apply to any binaries that require Tcl to operate
# properly (i.e. the text fixture, etc).
@@ -327,6 +312,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_CARRAY=1
!ENDIF
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
!ENDIF
@@ -349,6 +335,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PREUPDATE_HOOK=1
# Always enable math functions on Windows
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_PERCENTILE
# Should the rbu extension be enabled? If so, add compilation options
# to enable it.
@@ -561,10 +548,14 @@ RCC = $(RC) -DSQLITE_OS_WIN=1 -I. -I$(TOP) $(RCOPTS) $(RCCOPTS)
!IF "$(PLATFORM)"=="x86"
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
!IFNDEF PLATFORM
CORE_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
SHELL_CCONV_OPTS = -Gz -guard:cf -DSQLITE_CDECL=__cdecl -DSQLITE_APICALL=__stdcall -DSQLITE_CALLBACK=__stdcall -DSQLITE_SYSAPI=__stdcall
!ELSE
CORE_CCONV_OPTS =
SHELL_CCONV_OPTS =
@@ -665,18 +656,6 @@ SHELL_LINK_OPTS = $(SHELL_CORE_LIB)
TCC = $(TCC) -FAcs
!ENDIF
# When compiling the library for use in the WinRT environment,
# the following compile-time options must be used as well to
# disable use of Win32 APIs that are not available and to enable
# use of Win32 APIs that are specific to Windows 8 and/or WinRT.
#
!IF $(FOR_WINRT)!=0
TCC = $(TCC) -DSQLITE_OS_WINRT=1
RCC = $(RCC) -DSQLITE_OS_WINRT=1
TCC = $(TCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
RCC = $(RCC) -DWINAPI_FAMILY=WINAPI_FAMILY_APP
!ENDIF
# C compiler options for the Windows 10 platform (needs MSVC 2015).
#
!IF $(FOR_WIN10)!=0
@@ -689,35 +668,29 @@ BCC = $(BCC) /d2guard4 -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
# USE_CRT_DLL option is set to force dynamically linking to the
# MSVC runtime library.
#
!IF $(FOR_WINRT)!=0 || $(USE_CRT_DLL)!=0
!IF $(USE_CRT_DLL)!=0
!IF $(DEBUG)>1
TCC = $(TCC) -MDd
BCC = $(BCC) -MDd
ZLIBCFLAGS = -nologo -MDd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MD
BCC = $(BCC) -MD
ZLIBCFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi
!ENDIF
!ELSE
!IF $(DEBUG)>1
TCC = $(TCC) -MTd
BCC = $(BCC) -MTd
ZLIBCFLAGS = -nologo -MTd -W3 -O2 -Oy- -Zi
!ELSE
TCC = $(TCC) -MT
BCC = $(BCC) -MT
ZLIBCFLAGS = -nologo -MT -W3 -O2 -Oy- -Zi
!ENDIF
!ENDIF
# 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.
#
!IF $(DEBUG)==0
TCC = $(TCC) -DNDEBUG
BCC = $(BCC) -DNDEBUG
RCC = $(RCC) -DNDEBUG
!ENDIF
!IF $(DEBUG)>0 || $(API_ARMOR)!=0 || $(FOR_WIN10)!=0
TCC = $(TCC) -DSQLITE_ENABLE_API_ARMOR=1
RCC = $(RCC) -DSQLITE_ENABLE_API_ARMOR=1
@@ -907,56 +880,6 @@ LTLINKOPTS = /NOLOGO
LTLIBOPTS = /NOLOGO
!ENDIF
# When compiling for use in the WinRT environment, the following
# linker option must be used to mark the executable as runnable
# only in the context of an application container.
#
!IF $(FOR_WINRT)!=0
LTLINKOPTS = $(LTLINKOPTS) /APPCONTAINER
!IF "$(VISUALSTUDIOVERSION)"=="12.0" || "$(VISUALSTUDIOVERSION)"=="14.0"
!IFNDEF STORELIBPATH
!IF "$(PLATFORM)"=="x86"
STORELIBPATH = $(CRTLIBPATH)\store
!ELSEIF "$(PLATFORM)"=="x64"
STORELIBPATH = $(CRTLIBPATH)\store\amd64
!ELSEIF "$(PLATFORM)"=="ARM"
STORELIBPATH = $(CRTLIBPATH)\store\arm
!ELSE
STORELIBPATH = $(CRTLIBPATH)\store
!ENDIF
!ENDIF
STORELIBPATH = $(STORELIBPATH:\\=\)
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(STORELIBPATH)"
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, an extra library path is
# required.
#
!IF $(USE_WP81_OPTS)!=0
!IFNDEF WP81LIBPATH
!IF "$(PLATFORM)"=="x86"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ELSEIF "$(PLATFORM)"=="ARM"
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\ARM
!ELSE
WP81LIBPATH = $(PROGRAMFILES_X86)\Windows Phone Kits\8.1\lib\x86
!ENDIF
!ENDIF
!ENDIF
# When compiling for Windows Phone 8.1, some extra linker options
# are also required.
#
!IF $(USE_WP81_OPTS)!=0
!IFDEF WP81LIBPATH
LTLINKOPTS = $(LTLINKOPTS) "/LIBPATH:$(WP81LIBPATH)"
!ENDIF
LTLINKOPTS = $(LTLINKOPTS) /DYNAMICBASE
LTLINKOPTS = $(LTLINKOPTS) WindowsPhoneCore.lib RuntimeObject.lib PhoneAppModelHost.lib
LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:kernel32.lib /NODEFAULTLIB:ole32.lib
!ENDIF
# When compiling for UWP or the Windows 10 platform, some extra linker
# options are also required.
#
@@ -980,9 +903,9 @@ LTLINKOPTS = $(LTLINKOPTS) /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib
# If either debugging or symbols are enabled, enable PDBs.
#
!IF $(DEBUG)>1 || $(SYMBOLS)!=0
LDFLAGS = /DEBUG $(LDOPTS)
LDFLAGS = /NODEFAULTLIB:msvcrt /DEBUG $(LDOPTS)
!ELSE
LDFLAGS = $(LDOPTS)
LDFLAGS = /NODEFAULTLIB:msvcrt $(LDOPTS)
!ENDIF
@@ -1015,8 +938,10 @@ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_DQS=0
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1
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_PERCENTILE=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_ENABLE_BYTECODE_VTAB=1
SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_STRICT_SUBTYPE=1
!ENDIF
@@ -1065,6 +990,8 @@ $(SQLITE3EXE): shell.c $(SHELL_CORE_DEP) $(LIBRESOBJS) $(SHELL_CORE_SRC) $(SQLIT
/link $(SQLITE3EXEPDB) $(LDFLAGS) $(LTLINKOPTS) $(SHELL_LINK_OPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LIBREADLINE) $(LTLIBS) $(TLIBS)
tclsqlite-ex.c:
# Rule to build the amalgamation
#
sqlite3.lo: $(SQLITE3C)
+1 -1
View File
@@ -1 +1 @@
3.50.4
3.53.1
+15 -4
View File
@@ -375,18 +375,29 @@ configure process, and check it in.
Patching Autosetup for Project-local Changes
------------------------------------------------------------------------
The autosetup files require the following patches after updating
from their upstream sources:
### `--debug` flag
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 this project has a long history of
using `--enable-debug`, 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).
writing) four small edits in
[/autosetup/autosetup](/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.
### Fail on `malloc()` error
See [check-in 72c8a5b94cdf5d](/info/72c8a5b94cdf5d).
<a name="branch-customization"></a>
Branch-specific Customization
========================================================================
@@ -426,7 +437,7 @@ proc sqlite-custom-flags {} {
```
That function must return either an empty string or a list in the form
used internally by `sqlite-config.tcl:sqlite-configure`.
used internally by [sqlite-config.tcl][]'s `sqlite-configure`.
Next, define:
@@ -450,4 +461,4 @@ all other significant processing.
[sqlite-config.tcl]: /file/autosetup/sqlite-config.tcl
[Makefile.in]: /file/Makefile.in
[main.mk]: /file/main.mk
[JimTCL]: https://jim.tcl.tk
[JimTCL]: https://msteveb.github.io/jimtcl/
+11 -7
View File
@@ -406,8 +406,8 @@ proc options-add {opts} {
# 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 <dir>"
set opthelp $opt
# We no longer support documentation-only options, like "-C <dir>"
autosetup-error "Option $opt is not supported"
} elseif {$colon eq ""} {
# Boolean option
lappend autosetup(options) $name
@@ -1611,7 +1611,7 @@ proc autosetup_output_block {type lines} {
# Generate a command reference from inline documentation
proc automf_command_reference {} {
lappend files $::autosetup(prog)
lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/{*/*.tcl,*.tcl}]]
# We want to process all non-module files before module files
# and then modules in alphabetical order.
@@ -2124,7 +2124,7 @@ if {$autosetup(istcl)} {
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]
lappend stacktrace "" [dict get $frame file] [dict get $frame line] ""
}
}
return $stacktrace
@@ -2181,8 +2181,12 @@ 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] {
set vars {p f l cmd}
if {!$::autosetup(istcl) && ![dict exists $::tcl_platform stackFormat]} {
# Older versions of Jim had a 3 element stacktrace
set vars {p f l}
}
foreach $vars [stacktrace] {
if {[string match *.def $f]} {
return "[relative-path $f]:$l: Error: $msg"
}
@@ -2534,7 +2538,7 @@ 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"
puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
}
exit 1
}
+6 -4
View File
@@ -89,13 +89,15 @@ switch -glob -- [get-define host] {
define SH_SOPREFIX -Wl,-h,
}
}
*-*-hpux {
# XXX: These haven't been tested
define SHOBJ_CFLAGS "+O3 +z"
*-*-hpux* {
define SHOBJ_CFLAGS +z
define SHOBJ_LDFLAGS -b
define SH_CFLAGS +z
define SH_LDFLAGS -b
define SH_LINKFLAGS -Wl,+s
define LD_LIBRARY_PATH SHLIB_PATH
define SH_LINKRPATH "-Wl,+b -Wl,%s"
define SH_SOPREFIX -Wl,+h,
define STRIPLIBFLAGS -Wl,-s
}
*-*-haiku {
define SHOBJ_CFLAGS ""
+18 -29
View File
@@ -7409,11 +7409,13 @@ void *JimDefaultAllocator(void *ptr, size_t size)
free(ptr);
return NULL;
}
else if (ptr) {
return realloc(ptr, size);
}
else {
return malloc(size);
void *p = realloc(ptr, size);
if( p==0 ){
fprintf(stderr,"Out of memory\n");
exit(1);
}
return p;
}
}
@@ -9132,7 +9134,7 @@ int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
const char *sA = Jim_GetString(aObjPtr, &Alen);
const char *sB = Jim_GetString(bObjPtr, &Blen);
return Alen == Blen && *sA == *sB && memcmp(sA, sB, Alen) == 0;
return Alen == Blen && memcmp(sA, sB, Alen) == 0;
}
}
@@ -10242,7 +10244,7 @@ static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void
int len1, len2;
const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
return len1 == len2 && *str1 == *str2 && memcmp(str1, str2, len1) == 0;
return len1 == len2 && memcmp(str1, str2, len1) == 0;
}
static void JimCommandsHT_ValDestructor(void *interp, void *val)
@@ -13864,13 +13866,6 @@ static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
case JIM_EXPROP_NOT:
wC = !bA;
break;
case JIM_EXPROP_UNARYPLUS:
case JIM_EXPROP_UNARYMINUS:
rc = JIM_ERR;
Jim_SetResultFormatted(interp,
"can't use non-numeric string as operand of \"%s\"",
node->type == JIM_EXPROP_UNARYPLUS ? "+" : "-");
break;
default:
abort();
}
@@ -19875,22 +19870,16 @@ wrongargs:
}
else if (errorCodeObj) {
int len = Jim_ListLength(interp, argv[idx + 1]);
int i;
if (len > Jim_ListLength(interp, errorCodeObj)) {
ret = JIM_OK;
ret = -1;
}
else {
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;
}
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;
}
}
}
@@ -20266,7 +20255,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
}
case OPT_SET:
return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG | JIM_UNSHARED);
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);
@@ -20278,7 +20267,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
}
case OPT_UNSET:
if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_UNSHARED) != JIM_OK) {
if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
return JIM_ERR;
}
return JIM_OK;
+454 -141
View File
@@ -60,10 +60,11 @@
# $proj__Config is an internal-use-only array for storing whatever generic
# internal stuff we need stored.
#
array set ::proj__Config {
self-tests 1
}
array set ::proj__Config [subst {
self-tests [get-env proj.self-tests 0]
verbose-assert [get-env proj.assert-verbose 0]
isatty [isatty? stdout]
}]
#
# List of dot-in files to filter in the final stages of
@@ -75,7 +76,6 @@ array set ::proj__Config {
# See: proj-dot-ins-append and proj-dot-ins-process
#
set ::proj__Config(dot-in-files) [list]
set ::proj__Config(isatty) [isatty? stdout]
#
# @proj-warn msg
@@ -85,28 +85,29 @@ set ::proj__Config(isatty) [isatty? stdout]
#
proc proj-warn {args} {
show-notices
puts stderr [join [list "WARNING: \[[proj-scope 1]\]: " {*}$args] " "]
puts stderr [join [list "WARNING:" \[ [proj-scope 1] \]: {*}$args] " "]
}
#
# Internal impl of [proj-fatal] and [proj-error]. It must be called
# using tailcall.
proc proj__faterr {failMode argv} {
#
proc proj__faterr {failMode args} {
show-notices
set lvl 1
while {"-up" eq [lindex $argv 0]} {
set argv [lassign $argv -]
while {"-up" eq [lindex $args 0]} {
set args [lassign $args -]
incr lvl
}
if {$failMode} {
puts stderr [join [list "FATAL: \[[proj-scope $lvl]]: " {*}$argv]]
puts stderr [join [list "FATAL:" \[ [proj-scope $lvl] \]: {*}$args]]
exit 1
} else {
error [join [list "\[[proj-scope $lvl]]:" {*}$argv]]
error [join [list in \[ [proj-scope $lvl] \]: {*}$args]]
}
}
#
# @proj-fatal ?-up...? msg...
#
@@ -118,7 +119,7 @@ proc proj__faterr {failMode argv} {
# additional level.
#
proc proj-fatal {args} {
tailcall proj__faterr 1 $args
tailcall proj__faterr 1 {*}$args
}
#
@@ -127,10 +128,9 @@ proc proj-fatal {args} {
# Works like proj-fatal but uses [error] intead of [exit].
#
proc proj-error {args} {
tailcall proj__faterr 0 $args
tailcall proj__faterr 0 {*}$args
}
set ::proj__Config(verbose-assert) [get-env proj-assert-verbose 0]
#
# @proj-assert script ?message?
#
@@ -147,7 +147,7 @@ proc proj-assert {script {msg ""}} {
if {"" eq $msg} {
set msg $script
}
proj-fatal "Assertion failed in \[[proj-scope 1]\]: $msg"
tailcall proj__faterr 1 "Assertion failed:" $msg
}
}
@@ -378,8 +378,8 @@ proc proj-bin-define {binName {defName {}}} {
#
# 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).
# caller has no sensible way of knowing which [define] name it has
# unless they pass only a single argument).
#
proc proj-first-bin-of {args} {
set rc ""
@@ -451,7 +451,9 @@ proc proj-opt-set {flag {val 1}} {
# @proj-opt-exists flag
#
# Returns 1 if the given flag has been defined as a legal configure
# option, else returns 0.
# option, else returns 0. Options set via proj-opt-set "exist" for
# this purpose even if they were not defined via autosetup's
# [options] function.
#
proc proj-opt-exists {flag} {
expr {$flag in $::autosetup(options)};
@@ -555,7 +557,7 @@ proc proj-opt-define-bool {args} {
if {$invert} {
set rc [expr {!$rc}]
}
msg-result $rc
msg-result [string map {0 no 1 yes} $rc]
define $defName $rc
return $rc
}
@@ -704,11 +706,20 @@ proc proj-file-write {args} {
}
#
# @proj-check-compile-commands ?configFlag?
# @proj-check-compile-commands ?-assume-for-clang? ?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.
# Checks the compiler for compile_commands.json support. If
# $configFlag is not empty then it is assumed to be the name of an
# autosetup boolean config which controls whether to run/skip this
# check.
#
# If -assume-for-clang is provided and $configFlag is not empty and CC
# matches *clang* and no --$configFlag was explicitly provided to the
# configure script then behave as if --$configFlag had been provided.
# To disable that assumption, either don't pass -assume-for-clang or
# pass --$configFlag=0 to the configure script. (The reason for this
# behavior is that clang supports compile-commands but some other
# compilers report false positives with these tests.)
#
# Returns 1 if supported, else 0, and defines HAVE_COMPILE_COMMANDS to
# that value. Defines MAKE_COMPILATION_DB to "yes" if supported, "no"
@@ -716,12 +727,38 @@ proc proj-file-write {args} {
# HAVE_COMPILE_COMMANDS is preferred.
#
# ACHTUNG: this test has a long history of false positive results
# because of compilers reacting differently to the -MJ flag.
# because of compilers reacting differently to the -MJ flag. Because
# of this, it is recommended that this support be an opt-in feature,
# rather than an on-by-default default one. That is: in the
# configure script define the option as
# {--the-flag-name=0 => {Enable ....}}
#
proc proj-check-compile-commands {{configFlag {}}} {
proc proj-check-compile-commands {args} {
set i 0
set configFlag {}
set fAssumeForClang 0
set doAssume 0
msg-checking "compile_commands.json support... "
if {"" ne $configFlag && ![proj-opt-truthy $configFlag]} {
msg-result "explicitly disabled"
if {"-assume-for-clang" eq [lindex $args 0]} {
lassign $args - configFlag
incr fAssumeForClang
} elseif {1 == [llength $args]} {
lassign $args configFlag
} else {
proj-error "Invalid arguments"
}
if {1 == $fAssumeForClang && "" ne $configFlag} {
if {[string match *clang* [get-define CC]]
&& ![proj-opt-was-provided $configFlag]
&& ![proj-opt-truthy $configFlag]} {
proj-indented-notice [subst -nocommands -nobackslashes {
CC appears to be clang, so assuming that --$configFlag is likely
to work. To disable this assumption use --$configFlag=0.}]
incr doAssume
}
}
if {!$doAssume && "" ne $configFlag && ![proj-opt-truthy $configFlag]} {
msg-result "check disabled. Use --${configFlag} to enable it."
define HAVE_COMPILE_COMMANDS 0
define MAKE_COMPILATION_DB no
return 0
@@ -730,7 +767,7 @@ proc proj-check-compile-commands {{configFlag {}}} {
# 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"
msg-result "compiler supports -MJ. Assuming it's useful for compile_commands.json"
define MAKE_COMPILATION_DB yes; # deprecated
define HAVE_COMPILE_COMMANDS 1
return 1
@@ -885,7 +922,9 @@ proc proj-looks-like-windows {{key host}} {
#
proc proj-looks-like-mac {{key host}} {
switch -glob -- [get-define $key] {
*apple* {
*-*-darwin* {
# https://sqlite.org/forum/forumpost/7b218c3c9f207646
# There's at least one Linux out there which matches *apple*.
return 1
}
default {
@@ -927,17 +966,13 @@ proc proj-exe-extension {} {
#
proc proj-dll-extension {} {
set inner {{key} {
switch -glob -- [get-define $key] {
*apple* {
return ".dylib"
}
*-*-ming* - *-*-cygwin - *-*-msys {
return ".dll"
}
default {
return ".so"
}
if {[proj-looks-like-mac $key]} {
return ".dylib"
}
if {[proj-looks-like-windows $key]} {
return ".dll"
}
return ".so"
}}
define BUILD_DLLEXT [apply $inner build]
define TARGET_DLLEXT [apply $inner host]
@@ -1135,6 +1170,10 @@ proc proj-check-rpath {} {
if {"" eq $wl} {
set wl [proj-cc-check-Wl-flag -R$lp]
}
if {"" eq $wl} {
# HP-UX: https://sqlite.org/forum/forumpost/d80ecdaddd
set wl [proj-cc-check-Wl-flag +b $lp]
}
define LDFLAGS_RPATH $wl
}
}
@@ -1144,7 +1183,7 @@ proc proj-check-rpath {} {
#
# @proj-check-soname ?libname?
#
# Checks whether CC supports the -Wl,soname,lib... flag. If so, it
# 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.
@@ -1160,6 +1199,10 @@ proc proj-check-soname {{libname "libfoo.so.0"}} {
if {[cc-check-flags "-Wl,-soname,${libname}"]} {
define LDFLAGS_SONAME_PREFIX "-Wl,-soname,"
return 1
} elseif {[cc-check-flags "-Wl,+h,${libname}"]} {
# HP-UX: https://sqlite.org/forum/forumpost/d80ecdaddd
define LDFLAGS_SONAME_PREFIX "-Wl,+h,"
return 1
} else {
define LDFLAGS_SONAME_PREFIX ""
return 0
@@ -1606,7 +1649,7 @@ proc proj-tclConfig-sh-to-autosetup {tclConfigSh} {
#
# Similar modifications may be made for --mandir.
#
# Returns 1 if it modifies the environment, else 0.
# Returns >0 if it modifies the environment, else 0.
#
proc proj-tweak-default-env-dirs {} {
set rc 0
@@ -1645,7 +1688,11 @@ proc proj-tweak-default-env-dirs {} {
# processing the file. In the context of that script, the vars
# $dotInsIn and $dotInsOut will be set to the input and output file
# names. This can be used, for example, to make the output file
# executable or perform validation on its contents.
# executable or perform validation on its contents:
#
## proj-dot-ins-append my.sh.in my.sh {
## catch {exec chmod u+x $dotInsOut}
## }
#
# See [proj-dot-ins-process], [proj-dot-ins-list]
#
@@ -1665,7 +1712,7 @@ proc proj-dot-ins-append {fileIn args} {
proj-fatal "Too many arguments: $fileIn $args"
}
}
#puts "******* [proj-scope]: adding $fileIn"
#puts "******* [proj-scope]: adding [llength $fileIn]-length item: $fileIn"
lappend ::proj__Config(dot-in-files) $fileIn
}
@@ -1703,17 +1750,18 @@ proc proj-dot-ins-list {} {
# makes proj-dot-ins-append available for re-use.
#
proc proj-dot-ins-process {args} {
proj-parse-simple-flags args flags {
proj-parse-flags args flags {
-touch "" {return "-touch"}
-clear 0 {expr 1}
-validate 0 {expr 1}
}
#puts "args=$args"; parray flags
if {[llength $args] > 0} {
error "Invalid argument to [proj-scope]: $args"
}
foreach f $::proj__Config(dot-in-files) {
proj-assert {3==[llength $f]} \
"Expecting proj-dot-ins-list to be stored in 3-entry lists"
"Expecting proj-dot-ins-list to be stored in 3-entry lists. Got: $f"
lassign $f fIn fOut fScript
#puts "DOING $fIn ==> $fOut"
proj-make-from-dot-in {*}$flags(-touch) $fIn $fOut
@@ -1753,7 +1801,7 @@ proc proj-validate-no-unresolved-ats {args} {
set isMake [string match {*[Mm]ake*} $f]
foreach line [proj-file-content-list $f] {
if {!$isMake || ![string match "#*" [string trimleft $line]]} {
if {[regexp {(@[A-Za-z0-9_]+@)} $line match]} {
if {[regexp {(@[A-Za-z0-9_\.]+@)} $line match]} {
error "Unresolved reference to $match at line $lnno of $f"
}
}
@@ -1794,7 +1842,7 @@ proc proj-setup-autoreconfig {defName} {
}
#
# @prop-append-to defineName args...
# @prop-define-append defineName args...
#
# A proxy for Autosetup's [define-append]. Appends all non-empty $args
# to [define-append $defineName].
@@ -1825,7 +1873,7 @@ proc proj-define-append {defineName args} {
# but it is technically correct and still relevant on some
# environments.
#
# See: proj-append-to
# See: proj-define-append
#
proc proj-define-amend {args} {
set defName ""
@@ -1893,7 +1941,7 @@ proc proj-define-amend {args} {
#
proc proj-define-to-cflag {args} {
set rv {}
proj-parse-simple-flags args flags {
proj-parse-flags args flags {
-list 0 {expr 1}
-quote 0 {expr 1}
-zero-undef 0 {expr 1}
@@ -2001,7 +2049,7 @@ proc proj-cache-key {arg {addLevel 0}} {
# See proj-cache-key for -key's and -level's semantics, noting that
# this function adds one to -level for purposes of that call.
proc proj-cache-set {args} {
proj-parse-simple-flags args flags {
proj-parse-flags args flags {
-key => 0
-level => 0
}
@@ -2037,7 +2085,7 @@ proc proj-cache-remove {{key 0} {addLevel 0}} {
# See proj-cache-key for $key's and $addLevel's semantics, noting that
# this function adds one to $addLevel for purposes of that call.
proc proj-cache-check {args} {
proj-parse-simple-flags args flags {
proj-parse-flags args flags {
-key => 0
-level => 0
}
@@ -2070,147 +2118,316 @@ proc proj-coalesce {args} {
}
#
# @proj-parse-simple-flags ...
# @proj-parse-flags argvListName targetArrayName {prototype}
#
# A helper to parse flags from proc argument lists.
#
# Expects a list of arguments to parse, an array name to store any
# -flag values to, and a prototype object which declares the flags.
# The first argument is the name of a var holding the args to
# parse. It will be overwritten, possibly with a smaller list.
#
# The prototype must be a list in one of the following forms:
# The second argument is the name of an array variable to create in
# the caller's scope.
#
# -flag defaultValue {script}
# The third argument, $prototype, is a description of how to handle
# the flags. Each entry in that list must be in one of the
# following forms:
#
# -flag => defaultValue
# -----^--^ (with spaces there!)
# -flag defaultValue ?-literal|-call|-apply?
# script|number|incr|proc-name|{apply $aLambda}
#
# Repeated for each flag.
# -flag* ...as above...
#
# The first form represents a basic flag with no associated
# following argument. The second form extracts its value
# from the following argument in $argvName.
# -flag => defaultValue ?-call proc-name-and-args|-apply lambdaExpr?
#
# The first argument to this function is the name of a var holding the
# args to parse. It will be overwritten, possibly with a smaller list.
# -flag* => ...as above...
#
# The second argument the name of an array variable to create in the
# caller's scope. (Pneumonic: => points to the next argument.)
# :PRAGMA
#
# For the first form of flag, $script is run in the caller's scope if
# $argv contains -flag, and the result of that script is the new value
# for $tgtArrayName(-flag). This function intercepts [return $val]
# from $script. Any empty script will result in the flag having ""
# assigned to it.
# The first two forms represents a basic flag with no associated
# following argument. The third and fourth forms, called arg-consuming
# flags, extract the value from the following argument in $argvName
# (pneumonic: => points to the next argument.). The :PRAGMA form
# offers a way to configure certain aspects of this call.
#
# The args list is only inspected until the first argument which is
# not described by $prototype. i.e. the first "non-flag" (not counting
# values consumed for flags defined like --flag=>default).
# If $argv contains any given flag from $prototype, its default value
# is overridden depending on several factors:
#
# - If the -literal flag is used, or the flag's script is a number,
# value is used verbatim.
#
# - Else if the -call flag is used, the argument must be a proc name
# and any leading arguments, e.g. {apply $myLambda}. The proc is passed
# the (flag, value) as arguments (non-consuming flags will get
# passed the flag's current/starting value and consuming flags will
# get the next argument). Its result becomes the result of the
# flag.
#
# - Else if -apply X is used, it's effectively shorthand for -call
# {apply X}. Its argument may either be a $lambaRef or a {{f v}
# {body}} construct.
#
# - Else if $script is one of the following values, it is treated as
# the result of...
#
# - incr: increments the current value of the flag.
#
# - Else $script is eval'd to get its result value. That result
# becomes the new flag value for $tgtArrayName(-flag). This
# function intercepts [return $val] from eval'ing $script. Any
# empty script will result in the flag having "" assigned to it.
#
# Unless the -flag has a trailing asterisk, e.g. -flag*, this function
# assumes that each flag is unique, and using a flag more than once
# causes an error to be triggered. the -flag* forms works similarly
# except that may appear in $argv any number of times:
#
# - For non-arg-consuming flags, each invocation of -flag causes the
# result of $script to overwrite the previous value. e.g. so
# {-flag* {x} {incr foo}} has a default value of x, but passing in
# -flag twice would change it to the result of incrementing foo
# twice. This form can be used to implement, e.g., increasing
# verbosity levels by passing -verbose multiple times.
#
# - For arg-consuming flags, the given flag starts with value X, but
# if the flag is provided in $argv, the default is cleared, then
# each instance of -flag causes its value to be appended to the
# result, so {-flag* => {a b c}} defaults to {a b c}, but passing
# in -flag y -flag z would change it to {y z}, not {a b c y z}..
#
# By default, the args list is only inspected until the first argument
# which is not described by $prototype. i.e. the first "non-flag" (not
# counting values consumed for flags defined like -flag => default).
# The :all-flags pragma (see below) can modify this behavior.
#
# If a "--" flag is encountered, no more arguments are inspected as
# flags. If "--" is the first non-flag argument, the "--" flag is
# removed from the results but all remaining arguments are passed
# through. If "--" appears after the first non-flag, it is retained.
# flags unless the :all-flags pragma (see below) is in effect. The
# first instance of "--" is removed from the target result list but
# all remaining instances of "--" are are passed through.
#
# This function assumes that each flag is unique, and using a flag
# more than once behaves in a last-one-wins fashion.
# Any argvName entries not described in $prototype are considered to
# be "non-flags" for purposes of this function, even if they
# ostensibly look like flags.
#
# Any argvName entries not described in $prototype are not treated as
# flags.
#
# Returns the number of flags it processed in $argvName.
# Returns the number of flags it processed in $argvName, not counting
# "--".
#
# Example:
#
# set args [list -foo -bar {blah} 8 9 10 -theEnd]
# proj-parse-simple-flags args flags {
# -foo 0 {expr 1}
# -bar => 0
# -no-baz 2 {return 0}
# }
## set args [list -foo -bar {blah} -z 8 9 10 -theEnd]
## proj-parse-flags args flags {
## -foo 0 {expr 1}
## -bar => 0
## -no-baz 1 {return 0}
## -z 0 2
## }
#
# After that $flags would contain {-foo 1 -bar {blah} -no-baz 2}
# After that $flags would contain {-foo 1 -bar {blah} -no-baz 1 -z 2}
# and $args would be {8 9 10 -theEnd}.
#
# Potential TODOs: consider using lappend instead of set so that any
# given flag can be used more than once. Or add a syntax to indicate
# that multiples are allowed. Also consider searching the whole
# argv list, rather than stopping at the first non-flag
# Pragmas:
#
proc proj-parse-simple-flags {argvName tgtArrayName prototype} {
# Passing :PRAGMAS to this function may modify how it works. The
# following pragmas are supported (note the leading ":"):
#
# :all-flags indicates that the whole input list should be scanned,
# not stopping at the first non-flag or "--".
#
proc proj-parse-flags {argvName tgtArrayName prototype} {
upvar $argvName argv
upvar $tgtArrayName tgt
array set dflt {}
array set scripts {}
array set consuming {}
upvar $tgtArrayName outFlags
array set flags {}; # staging area
array set blob {}; # holds markers for various per-key state and options
set incrSkip 1; # 1 if we stop at the first non-flag, else 0
# Parse $prototype for flag definitions...
set n [llength $prototype]
# Figure out what our flags are...
set checkProtoFlag {
#puts "**** checkProtoFlag #$i of $n k=$k fv=$fv"
switch -exact -- $fv {
-literal {
proj-assert {![info exists blob(${k}.consumes)]}
set blob(${k}.script) [list expr [lindex $prototype [incr i]]]
}
-apply {
set fv [lindex $prototype [incr i]]
if {2 == [llength $fv]} {
# Treat this as a lambda literal
set fv [list $fv]
}
lappend blob(${k}.call) "apply $fv"
}
-call {
# arg is either a proc name or {apply $aLambda}
set fv [lindex $prototype [incr i]]
lappend blob(${k}.call) $fv
}
default {
proj-assert {![info exists blob(${k}.consumes)]}
set blob(${k}.script) $fv
}
}
if {$i >= $n} {
proj-error -up "[proj-scope]: Missing argument for $k flag"
}
}
for {set i 0} {$i < $n} {incr i} {
set k [lindex $prototype $i]
#puts "**** #$i of $n k=$k"
proj-assert {[string match -* $k]} \
"Invalid flag value: $k"
set v ""
set s ""
switch -exact -- [lindex $prototype [expr {$i + 1}]] {
=> {
incr i 2
if {$i >= $n} {
proj-error "Missing argument for $k => flag"
}
set consuming($k) 1
set v [lindex $prototype $i]
}
default {
set v [lindex $prototype [incr i]]
set s [lindex $prototype [incr i]]
set scripts($k) $s
# Check for :PRAGMA...
switch -exact -- $k {
:all-flags {
set incrSkip 0
continue
}
}
#puts "**** #$i of $n k=$k v=$v s=$s"
set dflt($k) $v
proj-assert {[string match -* $k]} \
"Invalid argument: $k"
if {[string match {*\*} $k]} {
# Re-map -foo* to -foo and flag -foo as a repeatable flag
set k [string map {* ""} $k]
incr blob(${k}.multi)
}
if {[info exists flags($k)]} {
proj-error -up "[proj-scope]: Duplicated prototype for flag $k"
}
switch -exact -- [lindex $prototype [expr {$i + 1}]] {
=> {
# -flag => DFLT ?-subflag arg?
incr i 2
if {$i >= $n} {
proj-error -up "[proj-scope]: Missing argument for $k => flag"
}
incr blob(${k}.consumes)
set vi [lindex $prototype $i]
if {$vi in {-apply -call}} {
proj-error -up "[proj-scope]: Missing default value for $k flag"
} else {
set fv [lindex $prototype [expr {$i + 1}]]
if {$fv in {-apply -call}} {
incr i
eval $checkProtoFlag
}
}
}
default {
# -flag VALUE ?flag? SCRIPT
set vi [lindex $prototype [incr i]]
set fv [lindex $prototype [incr i]]
eval $checkProtoFlag
}
}
#puts "**** #$i of $n k=$k vi=$vi"
set flags($k) $vi
}
# Now look for those flags in the source list
array set tgt [array get dflt]
unset dflt
#puts "-- flags"; parray flags
#puts "-- blob"; parray blob
set rc 0
set rv {}
set rv {}; # staging area for the target argv value
set skipMode 0
set n [llength $argv]
# Now look for those flags in $argv...
for {set i 0} {$i < $n} {incr i} {
set arg [lindex $argv $i]
#puts "-- [proj-scope] arg=$arg"
if {$skipMode} {
lappend rv $arg
} elseif {"--" eq $arg} {
incr skipMode
} elseif {[info exists tgt($arg)]} {
if {[info exists consuming($arg)]} {
if {$i + 1 >= $n} {
proj-assert 0 {Cannot happen - bounds already checked}
# "--" is the conventional way to end processing of args
if {[incr blob(--)] > 1} {
# Elide only the first one
lappend rv $arg
}
incr skipMode $incrSkip
} elseif {[info exists flags($arg)]} {
# A known flag...
set isMulti [info exists blob(${arg}.multi)]
incr blob(${arg}.seen)
if {1 < $blob(${arg}.seen) && !$isMulti} {
proj-error -up [proj-scope] "$arg flag was used multiple times"
}
set vMode 0; # 0=as-is, 1=eval, 2=call
set isConsuming [info exists blob(${arg}.consumes)]
if {$isConsuming} {
incr i
if {$i >= $n} {
proj-error -up [proj-scope] "is missing argument for $arg flag"
}
set tgt($arg) [lindex $argv [incr i]]
} elseif {"" eq $scripts($arg)} {
set tgt($arg) ""
set vv [lindex $argv $i]
} elseif {[info exists blob(${arg}.script)]} {
set vMode 1
set vv $blob(${arg}.script)
} else {
#puts "**** running scripts($arg) $scripts($arg)"
set code [catch {uplevel 1 $scripts($arg)} xrc xopt]
#puts "**** tgt($arg)=$scripts($arg) code=$code rc=$rc"
if {$code in {0 2}} {
set tgt($arg) $xrc
} else {
return {*}$xopt $xrc
set vv $flags($arg)
}
if {[info exists blob(${arg}.call)]} {
set vMode 2
set vv [concat {*}$blob(${arg}.call) $arg $vv]
} elseif {$isConsuming} {
proj-assert {!$vMode}
# fall through
} elseif {"" eq $vv || [string is double -strict $vv]} {
set vMode 0
} elseif {$vv in {incr}} {
set vMode 0
switch -exact $vv {
incr {
set xx $flags($k); incr xx; set vv $xx; unset xx
}
default {
proj-error "Unhandled \$vv value $vv"
}
}
} else {
set vv [list eval $vv]
set vMode 1
}
if {$vMode} {
set code [catch [list uplevel 1 $vv] vv xopt]
if {$code ni {0 2}} {
return {*}$xopt $vv
}
}
if {$isConsuming && $isMulti} {
if {1 == $blob(${arg}.seen)} {
# On the first hit, overwrite the default with a new list.
set flags($arg) [list $vv]
} else {
# On subsequent hits, append to the list.
lappend flags($arg) $vv
}
} else {
set flags($arg) $vv
}
incr rc
} else {
incr skipMode
# Non-flag
incr skipMode $incrSkip
lappend rv $arg
}
}
set argv $rv
array set outFlags [array get flags]
#puts "-- rv=$rv argv=$argv flags="; parray flags
return $rc
}; # proj-parse-flags
#
# Older (deprecated) name of proj-parse-flags.
#
proc proj-parse-simple-flags {args} {
tailcall proj-parse-flags {*}$args
}
if {$::proj__Config(self-tests)} {
set __ova $::proj__Config(verbose-assert);
set ::proj__Config(verbose-assert) 1
puts "Running [info script] self-tests..."
# proj-cache...
apply {{} {
#proj-warn "Test code for proj-cache"
proj-assert {![proj-cache-check -key here check]}
@@ -2233,4 +2450,100 @@ if {$::proj__Config(self-tests)} {
proj-assert {"" eq [proj-cache-remove]}
proj-assert {"" eq $check}
}}
}
# proj-parse-flags ...
apply {{} {
set foo 3
set argv {-a "hi - world" -b -b -b -- -a {bye bye} -- -d -D c -a "" --}
proj-parse-flags argv flags {
:all-flags
-a* => "gets overwritten"
-b* 7 {incr foo}
-d 1 0
-D 0 1
}
#puts "-- argv = $argv"; parray flags;
proj-assert {"-- c --" eq $argv}
proj-assert {$flags(-a) eq "{hi - world} {bye bye} {}"}
proj-assert {$foo == 6}
proj-assert {$flags(-b) eq $foo}
proj-assert {$flags(-d) == 0}
proj-assert {$flags(-D) == 1}
set foo 0
foreach x $flags(-a) {
proj-assert {$x in {{hi - world} {bye bye} {}}}
incr foo
}
proj-assert {3 == $foo}
set argv {-a {hi world} -b -maybe -- -a {bye bye} -- -b c --}
set foo 0
proj-parse-flags argv flags {
-a => "aaa"
-b 0 {incr foo}
-maybe no -literal yes
}
#parray flags; puts "--- argv = $argv"
proj-assert {"-a {bye bye} -- -b c --" eq $argv}
proj-assert {$flags(-a) eq "hi world"}
proj-assert {1 == $flags(-b)}
proj-assert {"yes" eq $flags(-maybe)}
set argv {-f -g -a aaa -M -M -M -L -H -A AAA a b c}
set foo 0
set myLambda {{flag val} {
proj-assert {$flag in {-f -g -M}}
#puts "myLambda flag=$flag val=$val"
incr val
}}
proc myNonLambda {flag val} {
proj-assert {$flag in {-A -a}}
#puts "myNonLambda flag=$flag val=$val"
concat $val $val
}
proj-parse-flags argv flags {
-f 0 -call {apply $myLambda}
-g 2 -apply $myLambda
-h 3 -apply $myLambda
-H 30 33
-a => aAAAa -apply {{f v} {
set v
}}
-A => AaaaA -call myNonLambda
-B => 17 -call myNonLambda
-M* 0 -apply $myLambda
-L "" -literal $myLambda
}
rename myNonLambda ""
#puts "--- argv = $argv"; parray flags
proj-assert {$flags(-f) == 1}
proj-assert {$flags(-g) == 3}
proj-assert {$flags(-h) == 3}
proj-assert {$flags(-H) == 33}
proj-assert {$flags(-a) == {aaa}}
proj-assert {$flags(-A) eq "AAA AAA"}
proj-assert {$flags(-B) == 17}
proj-assert {$flags(-M) == 3}
proj-assert {$flags(-L) eq $myLambda}
set argv {-touch -validate}
proj-parse-flags argv flags {
-touch "" {return "-touch"}
-validate 0 1
}
#puts "----- argv = $argv"; parray flags
proj-assert {$flags(-touch) eq "-touch"}
proj-assert {$flags(-validate) == 1}
proj-assert {$argv eq {}}
set argv {-i -i -i}
proj-parse-flags argv flags {
-i* 0 incr
}
proj-assert {3 == $flags(-i)}
}}
set ::proj__Config(verbose-assert) $__ova
unset __ova
puts "Done running [info script] self-tests."
}; # proj- API self-tests
+182 -77
View File
@@ -1,7 +1,7 @@
# 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 autoconf sub-tree. This file requires
# functions from proj.tcl.
# functions from the project-agnostic proj.tcl.
if {[string first " " $autosetup(srcdir)] != -1} {
user-error "The pathname of the source tree\
@@ -11,7 +11,7 @@ if {[string first " " $autosetup(builddir)] != -1} {
user-error "The pathname of the build directory\
may not contain space characters"
}
#parray ::autosetup; exit 0
use proj
#
# We want the package version info to be emitted early on, but doing
@@ -65,11 +65,12 @@ array set sqliteConfig [subst [proj-strip-hash-comments {
# The list of feature --flags which the --all flag implies. This
# requires special handling in a few places.
#
all-flag-enables {fts4 fts5 rtree geopoly session}
all-flag-enables {fts4 fts5 rtree geopoly session dbpage dbstat carray}
#
# Default value for the --all flag. Can hypothetically be modified
# by non-canonical builds.
# by non-canonical builds (it was added for a Tcl extension build
# mode which was eventually removed).
#
all-flag-default 0
}]]
@@ -92,7 +93,7 @@ array set sqliteConfig [subst [proj-strip-hash-comments {
# sqlite-configure BUILD_NAME { build-specific configure script }
#
# There are snippets of build-mode-specific decision-making in
# [sqlite-configure-finalize]
# [sqlite-configure-finalize], which gets run after $configScript.
proc sqlite-configure {buildMode configScript} {
proj-assert {$::sqliteConfig(build-mode) eq "unknown"} \
"sqlite-configure must not be called more than once"
@@ -112,8 +113,10 @@ proc sqlite-configure {buildMode configScript} {
#
# Reference: https://msteveb.github.io/autosetup/developer/
#
# All configure flags must be described in an 'options' call. The
# general syntax is:
# All configure flags must be described in one or more calls to
# autosetup's [options] and [options-add] functions. The general
# syntax of the single argument to those functions is a list contain
# a mapping of flags to help text:
#
# FLAG => {Help text}
#
@@ -164,13 +167,18 @@ proc sqlite-configure {buildMode configScript} {
########################################################################
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
# 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.
# autosetup's [options] and [options-add] command. Each block
# which is applicable to $buildMode is passed on to
# [options-add]. The order of each Y and sub-Y is retained, which
# is significant for rendering of --help.
#
# Maintenance note: [options] does not support comments in
# options, but we filter this object through
# [proj-strip-hash-comments] to remove them before passing them on
# to [options].
# When writing {help text blocks}, be aware that:
#
@@ -180,7 +188,7 @@ proc sqlite-configure {buildMode configScript} {
# pretty-printed.
#
# B) Vars and commands are NOT expanded, but we use a [subst] call
# below which will replace (only) var refs.
# below which will replace (only) $var refs.
# Options for how to build the library
build-modes {
@@ -212,11 +220,19 @@ proc sqlite-configure {buildMode configScript} {
geopoly => {Enable the GEOPOLY extension}
rtree => {Enable the RTREE extension}
session => {Enable the SESSION extension}
dbpage => {Enable the sqlite3_dbpage extension}
dbstat => {Enable the sqlite3_dbstat extension}
carray=1 => {Disable the CARRAY extension}
all=$::sqliteConfig(all-flag-default) => {$allFlagHelp}
largefile=1
=> {This legacy flag has no effect on the library but may influence
the generated sqlite_cfg.h by adding #define HAVE_LFS}
}
{canonical} {
column-metadata => {Enable the column metadata APIs}
# ^^^ Affects how sqlite3.c is generated, so is not available in
# the autoconf build.
}
}
# Options for TCL support
@@ -227,8 +243,6 @@ proc sqlite-configure {buildMode configScript} {
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.}
}
{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.
@@ -236,11 +250,10 @@ proc sqlite-configure {buildMode configScript} {
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
tclConfig.sh and (B) all TCL-based code generation. Use --with-tcl
unless you have a specific need for this flag. Warning: if its
containing dir has multiple tclsh versions, it may select the
wrong tclConfig.sh!}
}
{canonical} {
static-tclsqlite3=0
=> {Statically-link tclsqlite3. This only works if TCL support is
enabled and all requisite libraries are available in
@@ -319,7 +332,7 @@ proc sqlite-configure {buildMode configScript} {
Needed only by ext/wasm. Default=EMSDK env var.}
amalgamation-extra-src:FILES
=> {Space-separated list of soure files to append as-is to the resulting
=> {Space-separated list of source files to append as-is to the resulting
sqlite3.c amalgamation file. May be provided multiple times.}
}
}
@@ -334,8 +347,7 @@ proc sqlite-configure {buildMode configScript} {
=> {Link the sqlite3 shell app against the DLL instead of embedding sqlite3.c}
}
{canonical autoconf} {
# A potential TODO without a current use case:
#rpath=1 => {Disable use of the rpath linker flag}
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
@@ -406,7 +418,6 @@ proc sqlite-configure {buildMode configScript} {
# ^^^ lappend of [sqlite-custom-flags] introduces weirdness if
# we delay [proj-strip-hash-comments] until after that.
########################################################################
# sqlite-custom.tcl is intended only for vendor-branch-specific
# customization. See autosetup/README.md#branch-customization for
@@ -424,6 +435,8 @@ proc sqlite-configure {buildMode configScript} {
}
}
#lappend allFlags just-testing {{*} {soname:=duplicateEntry => {x}}}
# Filter allFlags to create the set of [options] legal for this build
foreach {group XY} [subst -nobackslashes -nocommands $allFlags] {
foreach {X Y} $XY {
@@ -432,7 +445,7 @@ proc sqlite-configure {buildMode configScript} {
}
}
}
#lappend opts "soname:=duplicateEntry => {x}"; #just testing
if {[catch {options {}} msg xopts]} {
# Workaround for <https://github.com/msteveb/autosetup/issues/73>
# where [options] behaves oddly on _some_ TCL builds when it's
@@ -447,8 +460,9 @@ proc sqlite-configure {buildMode configScript} {
########################################################################
# Runs "phase 1" of the configure process: after initial --flags
# handling but before the build-specific parts are run. $buildMode
# must be the mode which was passed to [sqlite-configure].
# handling but before sqlite-configure's $configScript argument is
# run. $buildMode must be the mode which was passed to
# [sqlite-configure].
proc sqlite-configure-phase1 {buildMode} {
define PACKAGE_NAME sqlite
define PACKAGE_URL {https://sqlite.org}
@@ -490,6 +504,7 @@ proc sqlite-configure-phase1 {buildMode} {
if {[file exists $srcdir/sqlite3.pc.in]} {
proj-dot-ins-append $srcdir/sqlite3.pc.in
}
sqlite-handle-hpux; # must be relatively early so that other config tests can work
}; # sqlite-configure-phase1
########################################################################
@@ -542,7 +557,25 @@ proc proc-debug {msg} {
}
define OPT_FEATURE_FLAGS {} ; # -DSQLITE_OMIT/ENABLE flags.
define OPT_SHELL {} ; # Feature-related CFLAGS for the sqlite3 CLI app
#
# OPT_SHELL = feature-related CFLAGS for the sqlite3 CLI app. The
# list's initial values are defaults which are always applied and not
# affected by --feature-flags. The list is appended to by various
# --feature-flags.
define OPT_SHELL {
-DSQLITE_DQS=0
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_RTREE
-DSQLITE_ENABLE_EXPLAIN_COMMENTS
-DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
-DSQLITE_ENABLE_STMTVTAB
-DSQLITE_ENABLE_DBPAGE_VTAB
-DSQLITE_ENABLE_DBSTAT_VTAB
-DSQLITE_ENABLE_BYTECODE_VTAB
-DSQLITE_ENABLE_OFFSET_SQL_FUNC
-DSQLITE_ENABLE_PERCENTILE
-DSQLITE_STRICT_SUBTYPE=1
}
########################################################################
# 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
@@ -616,7 +649,7 @@ proc sqlite-check-common-system-deps {} {
# Check for needed/wanted functions
cc-check-functions gmtime_r isnan localtime_r localtime_s \
strchrnul usleep utime pread pread64 pwrite pwrite64
usleep utime pread pread64 pwrite pwrite64
apply {{} {
set ldrt ""
@@ -646,6 +679,7 @@ proc sqlite-check-common-system-deps {} {
define HAVE_ZLIB 1
define LDFLAGS_ZLIB -lz
sqlite-add-shell-opt -DSQLITE_HAVE_ZLIB=1
sqlite-add-feature-flag -DSQLITE_HAVE_ZLIB=1
} else {
define HAVE_ZLIB 0
define LDFLAGS_ZLIB ""
@@ -709,12 +743,11 @@ proc sqlite-setup-default-cflags {} {
# 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)} {
# When cross-compiling we default to not using the -g flag, based
# on a /chat discussion prompted by
# https://sqlite.org/forum/forumpost/9a67df63eda9925c
lappend defaultCFlags -g
}
define CFLAGS [proj-get-env CFLAGS $defaultCFlags]
@@ -772,7 +805,12 @@ proc sqlite-handle-common-feature-flags {} {
sqlite-add-feature-flag -DSQLITE_ENABLE_MEMSYS3
}
}
scanstatus -DSQLITE_ENABLE_STMT_SCANSTATUS {}
bytecode-vtab -DSQLITE_ENABLE_BYTECODE_VTAB {}
scanstatus {-DSQLITE_ENABLE_STMT_SCANSTATUS -DSQLITE_ENABLE_BYTECODE_VTAB} {}
column-metadata -DSQLITE_ENABLE_COLUMN_METADATA {}
dbpage -DSQLITE_ENABLE_DBPAGE_VTAB {}
dbstat -DSQLITE_ENABLE_DBSTAT_VTAB {}
carray -DSQLITE_ENABLE_CARRAY {}
}] {
if {$boolFlag ni $::autosetup(options)} {
# Skip flags which are in the canonical build but not
@@ -1014,7 +1052,7 @@ proc sqlite-handle-emsdk {} {
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
# legacy configure script.
set dirs [list [get-define prefix]]
switch -glob -- [get-define host] {
*-linux-android {
@@ -1032,7 +1070,7 @@ proc sqlite-get-readline-dir-list {} {
if {[opt-val with-readline-ldflags] in {auto ""}} {
# If the user did not supply their own --with-readline-ldflags
# value, hijack that flag to inject options which are known to
# work on a default Haiku installation.
# work on Haiku OS installations.
if {"" ne [glob -nocomplain /boot/system/lib/libreadline*]} {
proj-opt-set with-readline-ldflags {-L/boot/system/lib -lreadline}
}
@@ -1082,8 +1120,8 @@ proc sqlite-get-readline-dir-list {} {
# 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.
# corresponding --FEATURE flag was explicitly given then fail
# fatally, else fail non-fatally.
proc sqlite-check-line-editing {} {
msg-result "Checking for line-editing capability..."
define HAVE_READLINE 0
@@ -1096,9 +1134,30 @@ proc sqlite-check-line-editing {} {
# if the library is not found.
set libsForReadline {readline edit} ; # -l<LIB> names to check for readline().
# The libedit check changes this.
set editLibName "readline" ; # "readline" or "editline"
set editLibName "readline" ; # "readline" or "editline"
set editLibDef "HAVE_READLINE" ; # "HAVE_READLINE" or "HAVE_EDITLINE"
set dirLn [opt-val with-linenoise]
# If none of --with-linenoise, --enable-readline, or --enable-editline
# are provided, but there exists a directory "linenoise" at $HOME or
# a sibling of the build or source directory, then try to use that linenoise
# direcctory.
#
if {"" eq $dirLn
&& ![proj-opt-was-provided readline]
&& ![proj-opt-was-provided editline]
} {
set dirlist ../linenoise
catch {lappend dirlist [file-normalize $::autosetup(srcdir)/../linenoise]}
catch {lappend dirlist $::env(HOME)/linenoise}
foreach d $dirlist {
if {[file exists $d/linenoise.c] && [file exists $d/linenoise.h]} {
set dirLn $d
break
}
}
}
if {"" ne $dirLn} {
# Use linenoise from a copy of its sources (not a library)...
if {![file isdir $dirLn]} {
@@ -1113,7 +1172,7 @@ proc sqlite-check-line-editing {} {
foreach f $lnCOpts {
if {[file exists $dirLn/$f]} {
set lnC $dirLn/$f
break;
break
}
}
if {"" eq $lnC} {
@@ -1134,6 +1193,8 @@ proc sqlite-check-line-editing {} {
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."
} else {
msg-result "Using linenoise at [file-normalize $dirLn]"
}
return "linenoise ($flavor)"
} elseif {[opt-bool editline]} {
@@ -1223,16 +1284,18 @@ proc sqlite-check-line-editing {} {
set rlLib [opt-val with-readline-ldflags]
#proc-debug "rlLib=$rlLib"
if {$rlLib in {auto ""}} {
set rlLib ""
set libTerm ""
if {[proj-check-function-in-lib tgetent "$editLibName ncurses curses termcap"]} {
set rlLib "" ; # make sure it's not "auto", as we may append to it below
set libTerm ""; # lib with tgetent(3)
if {[proj-check-function-in-lib tgetent [list $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} {
# tgetent(3) was found in the editing library
set rlLib $libTerm
} elseif {[proj-check-function-in-lib readline $libsForReadline $libTerm]} {
# tgetent(3) was found in an external lib
set rlLib [get-define lib_readline]
lappend rlLib $libTerm
undefine lib_readline
@@ -1262,8 +1325,8 @@ proc sqlite-check-line-editing {} {
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 {
if {![cctest -cflags "$rlInc -D${editLibDef}" -libs $rlLib -nooutput 1 \
-source {
#include <stdio.h>
#ifdef HAVE_EDITLINE
#include <editline/readline.h>
@@ -1316,7 +1379,7 @@ proc sqlite-handle-line-editing {} {
# - 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
# If --with-icu-config is used and neither pkg-config nor icu-config
# are found, fail fatally.
#
# If both --with-icu-ldflags and --with-icu-config are provided, they
@@ -1409,39 +1472,50 @@ proc sqlite-handle-icu {} {
# 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.
# feature. It may legally be empty on (A) some systems where
# dlopen() is in libc and (B) certain Unix-esque Windows
# environments which identify as Windows for SQLite's purposes so
# use LoadLibrary().
#
# - 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
set suffix ""
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.
switch -glob -- [get-define host] {
*-*-mingw* - *windows* {
incr found
set suffix "Using LoadLibrary()"
}
default {
set found [proj-check-function-in-lib dlopen dl]
if {$found} {
set suffix [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."
msg-result "Loadable extension support enabled. $suffix"
} else {
msg-result "Disabling loadable extension support. Use --enable-load-extension to enable them."
sqlite-add-feature-flag -DSQLITE_OMIT_LOAD_EXTENSION=1
@@ -1458,7 +1532,7 @@ proc sqlite-handle-math {} {
}
define LDFLAGS_MATH [get-define lib_ceil]
undefine lib_ceil
sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS
sqlite-add-feature-flag -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_PERCENTILE
msg-result "Enabling math SQL functions"
} {
define LDFLAGS_MATH ""
@@ -1520,6 +1594,19 @@ proc sqlite-handle-mac-install-name {} {
return $rc
}
#
# Checks specific to HP-UX.
#
proc sqlite-handle-hpux {} {
switch -glob -- [get-define host] {
*hpux* {
if {[cc-check-flags "-Ae"]} {
define-append CFLAGS -Ae
}
}
}
}
########################################################################
# Handles the --dll-basename configure flag. [define]'s
# SQLITE_DLL_BASENAME to the DLL's preferred base name (minus
@@ -1969,13 +2056,14 @@ proc sqlite-check-tcl {} {
# 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 ""]
set sq3Ver [get-define PACKAGE_VERSION]
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
set tcllibdir $i/sqlite${sq3Ver}
break
}
}
@@ -2111,15 +2199,31 @@ proc sqlite-determine-codegen-tcl {} {
# sqlite-determine-codegen-tcl.
proc sqlite-handle-tcl {} {
sqlite-check-tcl
if {"canonical" eq $::sqliteConfig(build-mode)} {
msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
if {"canonical" ne $::sqliteConfig(build-mode)} return
msg-result "TCL for code generation: [sqlite-determine-codegen-tcl]"
# Determine the base name of the Tcl extension's DLL
#
if {[get-define HAVE_TCL]} {
if {[string match *-cygwin [get-define host]]} {
set libname cyg
} else {
set libname lib
}
if {[get-define TCL_MAJOR_VERSION] > 8} {
append libname tcl9
}
append libname sqlite
} else {
set libname ""
}
define TCL_EXT_DLL_BASENAME $libname
# The extension is added in the makefile
}
########################################################################
# 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
@@ -2128,12 +2232,13 @@ proc sqlite-handle-rpath {} {
# 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 ""
# }
# https://sqlite.org/forum/forumpost/13cac3b56516f849
if {[proj-opt-truthy rpath]} {
proj-check-rpath
} else {
msg-result "Disabling use of rpath."
define LDFLAGS_RPATH ""
}
}
########################################################################
+82 -57
View File
@@ -92,6 +92,7 @@ array set teaish__Config [proj-strip-hash-comments {
-tm.tcl.in TEAISH_TM_TCL_IN
-options {}
-pragmas {}
-src {}
}
#
@@ -219,7 +220,9 @@ proc teaish-configure-core {} {
=> {Full pathname of tclsh to use. It is used for trying to find
tclConfig.sh. Warning: if its containing dir has multiple tclsh
versions, it may select the wrong tclConfig.sh!
Defaults to the $TCLSH environment variable.}
Defaults to the $TCLSH environment variable.}
tcl-stubs=0 => {Enable use of Tcl stubs library.}
# TEA has --with-tclinclude but it appears to only be useful for
# building an extension against an uninstalled copy of TCL's own
@@ -331,29 +334,33 @@ proc teaish-configure-core {} {
-url - -v ""
-tm.tcl - -v ""
-tm.tcl.in - -v ""
-src - -v ""
} {
#proj-assert 0 {Just testing}
set isPIFlag [expr {"-" ne $pflag}]
if {$isPIFlag} {
if {[info exists ::teaish__PkgInfo($pflag)]} {
# Was already set - skip it.
continue;
}
proj-assert {{-} eq $key}
proj-assert {{-} eq $key};# "Unexpected pflag=$pflag key=$key type=$type val=$val"
set key $f2d($pflag)
}
proj-assert {"" ne $key}
set got [get-define $key "<nope>"]
if {"<nope>" ne $got} {
# Was already set - skip it.
continue
if {"" ne $key} {
if {"<nope>" ne [get-define $key "<nope>"]} {
# Was already set - skip it.
continue
}
}
switch -exact -- $type {
-v {}
-e { set val [eval $val] }
default { proj-error "Invalid type flag: $type" }
}
#puts "***** defining default $pflag $key {$val} isPIFlag=$isPIFlag got=$got"
define $key $val
#puts "***** defining default $pflag $key {$val} isPIFlag=$isPIFlag"
if {$key ne ""} {
define $key $val
}
if {$isPIFlag} {
set ::teaish__PkgInfo($pflag) $val
}
@@ -493,6 +500,8 @@ proc teaish__configure_phase1 {} {
}
teaish-checks-run -post
define TEAISH_USE_STUBS [opt-bool tcl-stubs]
apply {{} {
# Set up "vsatisfies" code for pkgIndex.tcl.in,
# _teaish.tester.tcl.in, and for a configure-time check. We would
@@ -541,10 +550,10 @@ proc teaish__configure_phase1 {} {
define TEAISH_VSATISFIES_CODE [join $code "\n"]
}}; # vsatisfies
if {[proj-looks-like-windows] || [proj-looks-like-mac]} {
if {[proj-looks-like-windows]} {
# Without this, linking of an extension will not work on Cygwin or
# Msys2.
msg-result "Using USE_TCL_STUBS for this environment"
msg-result "Using USE_TCL_STUBS for Unix(ish)-on-Windows environment"
teaish-cflags-add -DUSE_TCL_STUBS=1
}
@@ -585,7 +594,8 @@ proc teaish__configure_phase1 {} {
#
if {0x0f & $::teaish__Config(pkginit-policy)} {
file delete -force -- [get-define TEAISH_PKGINIT_TCL]
proj-dot-ins-append [get-define TEAISH_PKGINIT_TCL_IN]
proj-dot-ins-append [get-define TEAISH_PKGINIT_TCL_IN] \
[get-define TEAISH_PKGINIT_TCL]
}
if {0x0f & $::teaish__Config(tm-policy)} {
file delete -force -- [get-define TEAISH_TM_TCL]
@@ -595,17 +605,20 @@ proc teaish__configure_phase1 {} {
apply {{} {
# Queue up any remaining dot-in files
set dotIns [list]
foreach d {
TEAISH_TESTER_TCL_IN
TEAISH_TEST_TCL_IN
TEAISH_MAKEFILE_IN
foreach {dIn => dOut} {
TEAISH_TESTER_TCL_IN => TEAISH_TESTER_TCL
TEAISH_TEST_TCL_IN => TEAISH_TEST_TCL
TEAISH_MAKEFILE_IN => TEAISH_MAKEFILE
} {
lappend dotIns [get-define $d ""]
lappend dotIns [get-define $dIn ""] [get-define $dOut ""]
}
lappend dotIns $::autosetup(srcdir)/Makefile.in; # must be after TEAISH_MAKEFILE_IN
foreach f $dotIns {
if {"" ne $f} {
proj-dot-ins-append $f
lappend dotIns $::autosetup(srcdir)/Makefile.in Makefile; # must be after TEAISH_MAKEFILE_IN.
# Much later: probably because of timestamps for deps purposes :-?
#puts "dotIns=$dotIns"
foreach {i o} $dotIns {
if {"" ne $i && "" ne $o} {
#puts " pre-dot-ins-append: \[$i\] -> \[$o\]"
proj-dot-ins-append $i $o
}
}
}}
@@ -640,10 +653,10 @@ proc teaish__configure_phase1 {} {
#
# NO [define]s after this point!
#
proj-dot-ins-process -validate
proj-if-opt-truthy teaish-dump-defines {
proj-file-write config.defines.txt $tdefs
}
proj-dot-ins-process -validate
}; # teaish__configure_phase1
@@ -1068,7 +1081,7 @@ If you are attempting an out-of-tree build, use
]]} {
if {[string match *.in $extM]} {
define TEAISH_MAKEFILE_IN $extM
define TEAISH_MAKEFILE [file rootname [file tail $extM]]
define TEAISH_MAKEFILE _[file rootname [file tail $extM]]
} else {
define TEAISH_MAKEFILE_IN ""
define TEAISH_MAKEFILE $extM
@@ -1136,8 +1149,8 @@ If you are attempting an out-of-tree build, use
set flist [list $dirExt/teaish.test.tcl.in $dirExt/teaish.test.tcl]
if {[proj-first-file-found ttt $flist]} {
if {[string match *.in $ttt]} {
# Generate teaish.test.tcl from $ttt
set xt [file rootname [file tail $ttt]]
# Generate _teaish.test.tcl from $ttt
set xt _[file rootname [file tail $ttt]]
file delete -force -- $xt; # ensure no stale copy is used
define TEAISH_TEST_TCL $xt
define TEAISH_TEST_TCL_IN $ttt
@@ -1304,7 +1317,6 @@ proc teaish-ldflags-prepend {args} {
# object files (which are typically in the build tree)).
#
proc teaish-src-add {args} {
set i 0
proj-parse-simple-flags args flags {
-dist 0 {expr 1}
-dir 0 {expr 1}
@@ -1389,7 +1401,7 @@ proc teaish__cleanup_rule {{tgt clean}} {
return ${tgt}-_${x}_
}
# @teaish-make-obj objfile srcfile ?...args?
# @teaish-make-obj ?flags? ?...args?
#
# Uses teaish-make-add to inject makefile rules for $objfile from
# $srcfile, which is assumed to be C code which uses libtcl. Unless
@@ -1403,43 +1415,45 @@ proc teaish__cleanup_rule {{tgt clean}} {
# Any arguments after the 2nd may be flags described below or, if no
# -recipe is provided, flags for the compiler call.
#
# -obj obj-filename.o
#
# -src src-filename.c
#
# -recipe {...}
# Uses the trimmed value of {...} as the recipe, prefixing it with
# a single hard-tab character.
#
# -deps {...}
# List of extra files to list as dependencies of $o. Good luck
# escaping non-trivial cases properly.
# List of extra files to list as dependencies of $o.
#
# -clean
# Generate cleanup rules as well.
proc teaish-make-obj {o src args} {
set consume 0
set clean 0
set flag ""
array set flags {}
set xargs {}
foreach arg $args {
if {$consume} {
set consume 0
set flags($flag) $arg
continue
}
switch -exact -- $arg {
-clean {incr clean}
-recipe -
-deps {
set flag $arg
incr consume
}
default {
lappend xargs $arg
}
proc teaish-make-obj {args} {
proj-parse-simple-flags args flags {
-clean 0 {expr 1}
-recipe => {}
-deps => {}
-obj => {}
-src => {}
}
#parray flags
if {"" eq $flags(-obj)} {
set args [lassign $args flags(-obj)]
if {"" eq $flags(-obj)} {
proj-error "Missing -obj flag."
}
}
foreach f {-deps -src} {
set flags($f) [string trim [string map {\n " "} $flags($f)]]
}
foreach f {-deps -src} {
set flags($f) [string trim $flags($f)]
}
#parray flags
#puts "-- args=$args"
teaish-make-add \
"# [proj-scope 1] -> [proj-scope] $o $src" -nl \
"$o: $src $::teaish__Config(teaish.tcl)"
"# [proj-scope 1] -> [proj-scope] $flags(-obj) $flags(-src)" -nl \
"$flags(-obj): $flags(-src) $::teaish__Config(teaish.tcl)"
if {[info exists flags(-deps)]} {
teaish-make-add " " [join $flags(-deps)]
}
@@ -1447,12 +1461,12 @@ proc teaish-make-obj {o src args} {
if {[info exists flags(-recipe)]} {
teaish-make-add [string trim $flags(-recipe)] -nl
} else {
teaish-make-add [join [list \$(CC.tcl) -c $src {*}$xargs]] -nl
teaish-make-add [join [list \$(CC.tcl) -c $flags(-src) {*}$args]] -nl
}
if {$clean} {
if {$flags(-clean)} {
set rule [teaish__cleanup_rule]
teaish-make-add \
"clean: $rule\n$rule:\n\trm -f \"$o\"\n"
"clean: $rule\n$rule:\n\trm -f \"$flags(-obj)\"\n"
}
}
@@ -2080,6 +2094,17 @@ proc teaish-pkginfo-set {args} {
set v $x
}
-src {
set d $::teaish__Config(extension-dir)
foreach f $v {
lappend ::teaish__Config(dist-files) $f
lappend ::teaish__Config(extension-src) $d/$f
lappend ::teaish__PkgInfo(-src) $f
# ^^^ so that default-value initialization in
# teaish-configure-core recognizes that it's been set.
}
}
-tm.tcl -
-tm.tcl.in {
if {0x30 & $::teaish__Config(pkgindex-policy)} {
@@ -2517,7 +2542,7 @@ proc teaish__install {{dDest ""}} {
] {
teaish__verbose 1 msg-result "Copying files to $destDir..."
file mkdir $destDir
foreach f [glob -directory $srcDir *] {
foreach f [glob -nocomplain -directory $srcDir *] {
if {[string match {*~} $f] || [string match "#*#" [file tail $f]]} {
# Editor-generated backups and emacs lock files
continue
+68 -3
View File
@@ -99,7 +99,7 @@ proc test__affert {failMode args} {
lassign $args script msg
}
incr ::test__Counters($what)
if {![uplevel 1 [concat expr [list $script]]]} {
if {![uplevel 1 expr [list $script]]} {
if {"" eq $msg} {
set msg $script
}
@@ -136,6 +136,40 @@ proc assert {args} {
tailcall test__affert 1 {*}$args
}
#
# @assert-matches ?-e? pattern ?-e? rhs ?msg?
#
# Equivalent to assert {[string match $pattern $rhs]} except that
# if either of those are prefixed with an -e flag, they are eval'd
# and their results are used.
#
proc assert-matches {args} {
set evalLhs 0
set evalRhs 0
if {"-e" eq [lindex $args 0]} {
incr evalLhs
set args [lassign $args -]
}
set args [lassign $args pattern]
if {"-e" eq [lindex $args 0]} {
incr evalRhs
set args [lassign $args -]
}
set args [lassign $args rhs msg]
if {$evalLhs} {
set pattern [uplevel 1 $pattern]
}
if {$evalRhs} {
set rhs [uplevel 1 $rhs]
}
#puts "***pattern=$pattern\n***rhs=$rhs"
tailcall test__affert 1 \
[join [list \[ string match [list $pattern] [list $rhs] \]]] $msg
# why does this not work? [list \[ string match [list $pattern] [list $rhs] \]] $msg
# "\[string match [list $pattern] [list $rhs]\]"
}
#
# @test-assert testId script ?msg?
#
@@ -157,7 +191,7 @@ proc test-expect {testId script result} {
puts "test $testId"
set x [string trim [uplevel 1 $script]]
set result [string trim $result]
tailcall test__affert 0 [list $x eq $result] \
tailcall test__affert 0 [list "{$x}" eq "{$result}"] \
"\nEXPECTED: <<$result>>\nGOT: <<$x>>"
}
@@ -169,7 +203,7 @@ proc test-expect {testId script result} {
#
proc test-catch {cmd args} {
if {[catch {
$cmd {*}$args
uplevel 1 $cmd {*}$args
} rc xopts]} {
puts "[test-current-scope] ignoring failure of: $cmd [lindex $args 0]: $rc"
return 1
@@ -177,6 +211,37 @@ proc test-catch {cmd args} {
return 0
}
#
# @test-catch-matching pattern (script|cmd args...)
#
# Works like test-catch, but it expects its argument(s) to to throw an
# error matching the given string (checked with [string match]). If
# they do not throw, or the error does not match $pattern, this
# function throws, else it returns 1.
#
# If there is no second argument, the $cmd is assumed to be a script,
# and will be eval'd in the caller's scope.
#
# TODO: add -glob and -regex flags to control matching flavor.
#
proc test-catch-matching {pattern cmd args} {
if {[catch {
#puts "**** catch-matching cmd=$cmd args=$args"
if {0 == [llength $args]} {
uplevel 1 $cmd {*}$args
} else {
$cmd {*}$args
}
} rc xopts]} {
if {[string match $pattern $rc]} {
return 1
} else {
error "[test-current-scope] exception does not match {$pattern}: {$rc}"
}
}
error "[test-current-scope] expecting to see an error matching {$pattern}"
}
if {![array exists ::teaish__BuildFlags]} {
array set ::teaish__BuildFlags {}
}
+2
View File
@@ -0,0 +1,2 @@
@echo off
nmake /f Makefile.msc %*
+9171 -5882
View File
File diff suppressed because it is too large Load Diff
+24 -4
View File
@@ -137,17 +137,37 @@ continue prompt = " ...> "
.sp
.fi
o If the file
o If the environment variable XDG_CONFIG_HOME is set then
.B ${XDG_CONFIG_HOME}/sqlite3/sqliterc
or
is checked, else
.B ~/.config/sqlite3/sqliterc
is checked. If the selected file does not exist then the fallback of
.B ~/.sqliterc
exists, the first of those to be found is processed during startup.
It should generally only contain meta-commands.
is used. It should generally only contain meta-commands.
o If the -init option is present, the specified file is processed.
o All other command line options are processed.
.SH HISTORY FILE
.B sqlite3
may be configured to use a history file to save SQL statements and
meta-commands entered interactively. These statements and commands can be
retrieved, edited and, reused at the main and continue prompts. If the
environment variable
.B SQLITE_HISTORY
is set, it will be used as the name of the history file, whether it
already exists or not. If it is not set but the XDG_STATE_HOME
environment variable is then
.B ${XDG_STATE_HOME}/sqlite_history
is used. If XDG_STATE_HOME is not set then
.B ~/.local/state/sqlite_history
is used. If the selected file does not exist then
.B ~/.sqlite_history
will be used as the history file. If any history file is found, it
will be written if the shell exits interactive mode normally,
regardless of whether it existed previously, though saving will
silently fail if the history file's directory does not exist.
.SH SEE ALSO
https://sqlite.org/cli.html
.br
+11180 -5219
View File
File diff suppressed because it is too large Load Diff
+753 -193
View File
File diff suppressed because it is too large Load Diff
+16
View File
@@ -368,6 +368,14 @@ struct sqlite3_api_routines {
int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
/* Version 3.50.0 and later */
int (*setlk_timeout)(sqlite3*,int,int);
/* Version 3.51.0 and later */
int (*set_errmsg)(sqlite3*,int,const char*);
int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
/* Version 3.52.0 and later */
void (*str_truncate)(sqlite3_str*,int);
void (*str_free)(sqlite3_str*);
int (*carray_bind)(sqlite3_stmt*,int,void*,int,int,void(*)(void*));
int (*carray_bind_v2)(sqlite3_stmt*,int,void*,int,int,void(*)(void*),void*);
};
/*
@@ -703,6 +711,14 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_set_clientdata sqlite3_api->set_clientdata
/* Version 3.50.0 and later */
#define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
/* Version 3.51.0 and later */
#define sqlite3_set_errmsg sqlite3_api->set_errmsg
#define sqlite3_db_status64 sqlite3_api->db_status64
/* Version 3.52.0 and later */
#define sqlite3_str_truncate sqlite3_api->str_truncate
#define sqlite3_str_free sqlite3_api->str_free
#define sqlite3_carray_bind sqlite3_api->carray_bind
#define sqlite3_carray_bind_v2 sqlite3_api->carray_bind_v2
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+1 -1
View File
@@ -1,3 +1,3 @@
#ifndef SQLITE_RESOURCE_VERSION
#define SQLITE_RESOURCE_VERSION 3,50,4
#define SQLITE_RESOURCE_VERSION 3,53,1
#endif
+54 -30
View File
@@ -119,7 +119,7 @@ TCLLIBDIR = @TCLLIBDIR@
# typically come from the ./configure command-line invocation).
#
CFLAGS.configure = @SH_CFLAGS@ @TEAISH_CFLAGS@ @CFLAGS@ @CPPFLAGS@ $(TCL_INCLUDE_SPEC)
#CFLAGS.configure += -DUSE_TCL_STUBS=1
CFLAGS.configure += -DUSE_TCL_STUBS=@TEAISH_USE_STUBS@
#
# LDFLAGS.configure = LDFLAGS as known at configure-time.
@@ -146,13 +146,14 @@ LDFLAGS.shlib = @SH_LDFLAGS@
# sources passed to [teaish-src-add], but may also be appended to by
# teaish.make.
#
tx.src =@TEAISH_EXT_SRC@
tx.src = @TEAISH_EXT_SRC@
#
# tx.CFLAGS is typically set by teaish.make, whereas TEAISH_CFLAGS
# gets set up via the configure script.
#
tx.CFLAGS =
tx.CPPFLAGS =
#
# tx.LDFLAGS is typically set by teaish.make, whereas TEAISH_LDFLAGS
@@ -167,6 +168,11 @@ tx.LDFLAGS =
#
tx.dist.files = @TEAISH_DIST_FILES@
#
# The base name for a distribution tar/zip file.
#
tx.dist.basename = $(tx.name.dist)-$(tx.version)
# List of deps which may trigger an auto-reconfigure.
#
teaish__autogen.deps = \
@@ -199,16 +205,21 @@ $(teaish.makefile): $(teaish__auto.def) $(teaish.makefile.in) \
@AUTODEPS@
@if TEAISH_TESTER_TCL_IN
@TEAISH_TESTER_TCL_IN@:
@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@
config.log: @TEAISH_TESTER_TCL@
@TEAISH_TESTER_TCL_IN@: $(teaish__autogen.deps)
config.log: @TEAISH_TESTER_TCL_IN@
@TEAISH_TESTER_TCL@: @TEAISH_TESTER_TCL_IN@
@endif
@if TEAISH_TEST_TCL_IN
@TEAISH_TEST_TCL_IN@: $(teaish__autogen.deps)
config.log: @TEAISH_TEST_TCL_IN@
@TEAISH_TEST_TCL@: @TEAISH_TEST_TCL_IN@
@endif
#
# CC variant for compiling Tcl-using sources.
#
CC.tcl = \
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS)
$(CC) -o $@ $(CFLAGS.configure) $(CFLAGS) $(tx.CFLAGS) $(tx.CPPFLAGS)
#
# CC variant for linking $(tx.src) into an extension DLL. Note that
@@ -217,7 +228,7 @@ CC.tcl = \
#
CC.dll = \
$(CC.tcl) $(tx.src) $(LDFLAGS.shlib) \
$(LDFLAGS.configure) $(LDFLAGS) $(tx.LDFLAGS) $(TCL_STUB_LIB_SPEC)
$(tx.LDFLAGS) $(LDFLAGS.configure) $(LDFLAGS) $(TCL_STUB_LIB_SPEC)
@if TEAISH_ENABLE_DLL
#
@@ -248,16 +259,25 @@ test-extension: # this name is reserved for use by teaish.make[.in]
test-prepre: $(tx.dll)
@endif
@if TEAISH_TESTER_TCL
test-core.args = @TEAISH_TESTER_TCL@
teaish.tester.tcl = @TEAISH_TESTER_TCL@
test-core.args = $(teaish.tester.tcl)
@if TEAISH_ENABLE_DLL
test-core.args += '$(tx.dll)' '$(tx.loadPrefix)'
@else
test-core.args += '' ''
@endif
test-core.args += @TEAISH_TESTUTIL_TCL@
# Clients may pass additional args via test.args=...
# and ::argv will be rewritten before the test script loads, to
# remove $(test-core.args)
test.args ?=
test-core: test-pre
$(TCLSH) $(test-core.args)
test-prepre: @TEAISH_TESTER_TCL@
$(TCLSH) $(test-core.args) $(test.args)
test-gdb: $(teaish.tester.tcl)
gdb --args $(TCLSH) $(test-core.args) $(test.args)
test-vg.flags ?= --leak-check=full -v --show-reachable=yes --track-origins=yes
test-vg: $(teaish.tester.tcl)
valgrind $(test-vg.flags) $(TCLSH) $(test-core.args) $(test.args)
@else # !TEAISH_TESTER_TCL
test-prepre:
@endif # TEAISH_TESTER_TCL
@@ -288,7 +308,7 @@ distclean-core: distclean-pre
@endif
@endif
@if TEAISH_TESTER_TCL_IN
rm -f @TEAISH_TESTER_TCL@
rm -f $(teaish.tester.tcl)
@endif
@if TEAISH_PKGINDEX_TCL_IN
rm -f @TEAISH_PKGINDEX_TCL@
@@ -355,10 +375,15 @@ install-core: install-pre
@endif
install-test: install-core
@echo "Post-install test of [package require $(tx.name.pkg) $(tx.version)]..."; \
set xtra=""; \
if [ x != "x$(DESTDIR)" ]; then \
xtra='set ::auto_path [linsert $$::auto_path 0 [file normalize $(DESTDIR)$(TCLLIBDIR)/..]];'; \
fi; \
if echo \
'set c 0; ' \
'set c 0; ' $$xtra \
'@TEAISH_POSTINST_PREREQUIRE@' \
'if {[catch {package require $(tx.name.pkg) $(tx.version)}]} {incr c};' \
'if {[catch {package require $(tx.name.pkg) $(tx.version)} xc]} {incr c};' \
'if {$$c && "" ne $$xc} {puts $$xc; puts "auto_path=$$::auto_path"};' \
'exit $$c' \
| $(TCLSH) ; then \
echo "passed"; \
@@ -406,7 +431,7 @@ config.log: $(teaish.makefile.in)
# recognized when running in --teaish-install mode, causing
# the sub-configure to fail.
dist.flags = --with-tclsh=$(TCLSH)
dist.reconfig = $(teaish.dir)/configure $(dist.flags)
dist.reconfig = $(teaish.dir)/configure $(tx.dist.reconfig-flags) $(dist.flags)
# Temp dir for dist.zip. Must be different than dist.tgz or else
# parallel builds may hose the dist.
@@ -414,24 +439,23 @@ teaish__dist.tmp.zip = teaish__dist_zip
#
# Make a distribution zip file...
#
dist.basename = $(tx.name.dist)-$(tx.version)
dist.zip = $(dist.basename).zip
dist.zip = $(tx.dist.basename).zip
.PHONY: dist.zip dist.zip-core dist.zip-post
#dist.zip-pre:
# We apparently can't add a pre-hook here, else "make dist" rebuilds
# the archive each time it's run.
$(dist.zip): $(tx.dist.files)
@rm -fr $(teaish__dist.tmp.zip)
@mkdir -p $(teaish__dist.tmp.zip)/$(dist.basename)
@mkdir -p $(teaish__dist.tmp.zip)/$(tx.dist.basename)
@tar cf $(teaish__dist.tmp.zip)/tmp.tar $(tx.dist.files)
@tar xf $(teaish__dist.tmp.zip)/tmp.tar -C $(teaish__dist.tmp.zip)/$(dist.basename)
@tar xf $(teaish__dist.tmp.zip)/tmp.tar -C $(teaish__dist.tmp.zip)/$(tx.dist.basename)
@if TEAISH_DIST_FULL
@$(dist.reconfig) \
--teaish-install=$(teaish__dist.tmp.zip)/$(dist.basename) \
--t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null
--teaish-install=$(teaish__dist.tmp.zip)/$(tx.dist.basename) \
--t-e-d=$(teaish__dist.tmp.zip)/$(tx.dist.basename) >/dev/null
@endif
@rm -f $(dist.basename)/tmp.tar $(dist.zip)
@cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(dist.basename)
@rm -f $(tx.dist.basename)/tmp.tar $(dist.zip)
@cd $(teaish__dist.tmp.zip) && zip -q -r ../$(dist.zip) $(tx.dist.basename)
@rm -fr $(teaish__dist.tmp.zip)
@ls -la $(dist.zip)
dist.zip-core: $(dist.zip)
@@ -447,23 +471,23 @@ undist: undist-zip
# Make a distribution tarball...
#
teaish__dist.tmp.tgz = teaish__dist_tgz
dist.tgz = $(dist.basename).tar.gz
dist.tgz = $(tx.dist.basename).tar.gz
.PHONY: dist.tgz dist.tgz-core dist.tgz-post
# dist.tgz-pre:
# see notes in dist.zip
$(dist.tgz): $(tx.dist.files)
@rm -fr $(teaish__dist.tmp.tgz)
@mkdir -p $(teaish__dist.tmp.tgz)/$(dist.basename)
@mkdir -p $(teaish__dist.tmp.tgz)/$(tx.dist.basename)
@tar cf $(teaish__dist.tmp.tgz)/tmp.tar $(tx.dist.files)
@tar xf $(teaish__dist.tmp.tgz)/tmp.tar -C $(teaish__dist.tmp.tgz)/$(dist.basename)
@tar xf $(teaish__dist.tmp.tgz)/tmp.tar -C $(teaish__dist.tmp.tgz)/$(tx.dist.basename)
@if TEAISH_DIST_FULL
@rm -f $(teaish__dist.tmp.tgz)/$(dist.basename)/pkgIndex.tcl.in; # kludge
@rm -f $(teaish__dist.tmp.tgz)/$(tx.dist.basename)/pkgIndex.tcl.in; # kludge
@$(dist.reconfig) \
--teaish-install=$(teaish__dist.tmp.tgz)/$(dist.basename) \
--t-e-d=$(teaish__dist.tmp.zip)/$(dist.basename) >/dev/null
--teaish-install=$(teaish__dist.tmp.tgz)/$(tx.dist.basename) \
--t-e-d=$(teaish__dist.tmp.zip)/$(tx.dist.basename) >/dev/null
@endif
@rm -f $(dist.basename)/tmp.tar $(dist.tgz)
@cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(dist.basename)
@rm -f $(tx.dist.basename)/tmp.tar $(dist.tgz)
@cd $(teaish__dist.tmp.tgz) && tar czf ../$(dist.tgz) $(tx.dist.basename)
@rm -fr $(teaish__dist.tmp.tgz)
@ls -la $(dist.tgz)
dist.tgz-core: $(dist.tgz)
+4 -14
View File
@@ -83,22 +83,12 @@ script and then run make. For example:
$ cd sqlite-*-tea
$ ./configure --with-tcl=/path/to/tcl/install/root
$ make
$ make test
$ 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.
On Windows this build is known to work on Cygwin and some Msys2
environments. We do not currently support Microsoft makefiles for
native Windows builds.
+2 -1
View File
@@ -21,7 +21,8 @@ if {[llength [lindex $::argv 0]] > 0} {
# ----^^^^^^^ needed on Haiku when argv 0 is just a filename, else
# load cannot find the file.
}
source -encoding utf-8 [lindex $::argv 2]; # teaish/tester.tcl
set ::argv [lassign $argv - -]
source -encoding utf-8 [lindex $::argv 0]; # teaish/tester.tcl
@if TEAISH_PKGINIT_TCL
apply {{file} {
set dir [file dirname $::argv0]
+15 -2
View File
@@ -1,7 +1,20 @@
#!/bin/sh
# Look for and run autosetup...
dir0="`dirname "$0"`"
dirA="$dir0/../autosetup"
# This is the case ^^^^^^^^^^^^ in the SQLite "autoconf" bundle.
dirA="$dir0"
if [ -d $dirA/autosetup ]; then
# A local copy of autosetup
dirA=$dirA/autosetup
elif [ -d $dirA/../autosetup ]; then
# SQLite "autoconf" bundle
dirA=$dirA/../autosetup
elif [ -d $dirA/../../autosetup ]; then
# SQLite canonical source tree
dirA=$dirA/../../autosetup
else
echo "$0: Cannot find autosetup" 1>&2
exit 1
fi
WRAPPER="$0"; export WRAPPER; exec "`"$dirA/autosetup-find-tclsh"`" \
"$dirA/autosetup" --teaish-extension-dir="$dir0" \
"$@"
-15
View File
@@ -1,15 +0,0 @@
.TH sqlite3 n 4.1 "Tcl-Extensions"
.HS sqlite3 tcl
.BS
.SH NAME
sqlite3 \- an interface to the SQLite3 database engine
.SH SYNOPSIS
\fBsqlite3\fI command_name ?filename?\fR
.br
.SH DESCRIPTION
SQLite3 is a self-contains, zero-configuration, transactional SQL database
engine. This extension provides an easy to use interface for accessing
SQLite database files from Tcl.
.PP
For full documentation see \fIhttps://sqlite.org/\fR and
in particular \fIhttps://sqlite.org/tclsqlite.html\fR.
+505 -57
View File
@@ -54,6 +54,10 @@
# define CONST const
#elif !defined(Tcl_Size)
typedef int Tcl_Size;
# ifndef Tcl_BounceRefCount
# define Tcl_BounceRefCount(X) Tcl_IncrRefCount(X); Tcl_DecrRefCount(X)
/* https://www.tcl-lang.org/man/tcl9.0/TclLib/Object.html */
# endif
#endif
/**** End copy of tclsqlite.h ****/
@@ -125,6 +129,15 @@
/* Forward declaration */
typedef struct SqliteDb SqliteDb;
/* Add -DSQLITE_ENABLE_QRF_IN_TCL to add the Query Result Formatter (QRF)
** into the build of the TCL extension, when building using separate
** source files. The QRF is included automatically when building from
** the tclsqlite3.c amalgamation.
*/
#if defined(SQLITE_ENABLE_QRF_IN_TCL)
#include "qrf.h"
#endif
/*
** New SQL functions can be created as TCL scripts. Each such function
** is described by an instance of the following structure.
@@ -1089,7 +1102,9 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_DecrRefCount(pCmd);
}
if( rc && rc!=TCL_RETURN ){
if( TCL_BREAK==rc ){
sqlite3_result_null(context);
}else if( rc && rc!=TCL_RETURN ){
sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
@@ -1107,7 +1122,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}else if( (c=='b' && pVar->bytes==0 && strcmp(zType,"boolean")==0 )
|| (c=='b' && pVar->bytes==0 && strcmp(zType,"booleanString")==0 )
|| (c=='w' && strcmp(zType,"wideInt")==0)
|| (c=='i' && strcmp(zType,"int")==0)
|| (c=='i' && strcmp(zType,"int")==0)
){
eType = SQLITE_INTEGER;
}else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -1621,11 +1636,12 @@ struct DbEvalContext {
SqlPreparedStmt *pPreStmt; /* Current statement */
int nCol; /* Number of columns returned by pStmt */
int evalFlags; /* Flags used */
Tcl_Obj *pArray; /* Name of array variable */
Tcl_Obj *pVarName; /* Name of target array/dict variable */
Tcl_Obj **apColName; /* Array of column names */
};
#define SQLITE_EVAL_WITHOUTNULLS 0x00001 /* Unset array(*) for NULL */
#define SQLITE_EVAL_ASDICT 0x00002 /* Use dict instead of array */
/*
** Release any cache of column names currently held as part of
@@ -1646,20 +1662,20 @@ static void dbReleaseColumnNames(DbEvalContext *p){
/*
** Initialize a DbEvalContext structure.
**
** If pArray is not NULL, then it contains the name of a Tcl array
** If pVarName is not NULL, then it contains the name of a Tcl array
** variable. The "*" member of this array is set to a list containing
** the names of the columns returned by the statement as part of each
** call to dbEvalStep(), in order from left to right. e.g. if the names
** of the returned columns are a, b and c, it does the equivalent of the
** tcl command:
**
** set ${pArray}(*) {a b c}
** set ${pVarName}(*) {a b c}
*/
static void dbEvalInit(
DbEvalContext *p, /* Pointer to structure to initialize */
SqliteDb *pDb, /* Database handle */
Tcl_Obj *pSql, /* Object containing SQL script */
Tcl_Obj *pArray, /* Name of Tcl array to set (*) element of */
Tcl_Obj *pVarName, /* Name of Tcl array to set (*) element of */
int evalFlags /* Flags controlling evaluation */
){
memset(p, 0, sizeof(DbEvalContext));
@@ -1667,9 +1683,9 @@ static void dbEvalInit(
p->zSql = Tcl_GetString(pSql);
p->pSql = pSql;
Tcl_IncrRefCount(pSql);
if( pArray ){
p->pArray = pArray;
Tcl_IncrRefCount(pArray);
if( pVarName ){
p->pVarName = pVarName;
Tcl_IncrRefCount(pVarName);
}
p->evalFlags = evalFlags;
addDatabaseRef(p->pDb);
@@ -1692,7 +1708,7 @@ static void dbEvalRowInfo(
Tcl_Obj **apColName = 0; /* Array of column names */
p->nCol = nCol = sqlite3_column_count(pStmt);
if( nCol>0 && (papColName || p->pArray) ){
if( nCol>0 && (papColName || p->pVarName) ){
apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol );
for(i=0; i<nCol; i++){
apColName[i] = Tcl_NewStringObj(sqlite3_column_name(pStmt,i), -1);
@@ -1701,20 +1717,35 @@ static void dbEvalRowInfo(
p->apColName = apColName;
}
/* If results are being stored in an array variable, then create
** the array(*) entry for that array
/* If results are being stored in a variable then create the
** array(*) or dict(*) entry for that variable.
*/
if( p->pArray ){
if( p->pVarName ){
Tcl_Interp *interp = p->pDb->interp;
Tcl_Obj *pColList = Tcl_NewObj();
Tcl_Obj *pStar = Tcl_NewStringObj("*", -1);
Tcl_IncrRefCount(pColList);
Tcl_IncrRefCount(pStar);
for(i=0; i<nCol; i++){
Tcl_ListObjAppendElement(interp, pColList, apColName[i]);
}
Tcl_IncrRefCount(pStar);
Tcl_ObjSetVar2(interp, p->pArray, pStar, pColList, 0);
if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
Tcl_ObjSetVar2(interp, p->pVarName, pStar, pColList, 0);
}else{
Tcl_Obj * pDict = Tcl_ObjGetVar2(interp, p->pVarName, NULL, 0);
if( !pDict ){
pDict = Tcl_NewDictObj();
}else if( Tcl_IsShared(pDict) ){
pDict = Tcl_DuplicateObj(pDict);
}
if( Tcl_DictObjPut(interp, pDict, pStar, pColList)==TCL_OK ){
Tcl_ObjSetVar2(interp, p->pVarName, NULL, pDict, 0);
}
Tcl_BounceRefCount(pDict);
}
Tcl_DecrRefCount(pStar);
Tcl_DecrRefCount(pColList);
}
}
@@ -1756,7 +1787,7 @@ static int dbEvalStep(DbEvalContext *p){
if( rcs==SQLITE_ROW ){
return TCL_OK;
}
if( p->pArray ){
if( p->pVarName ){
dbEvalRowInfo(p, 0, 0);
}
rcs = sqlite3_reset(pStmt);
@@ -1807,9 +1838,9 @@ static void dbEvalFinalize(DbEvalContext *p){
dbReleaseStmt(p->pDb, p->pPreStmt, 0);
p->pPreStmt = 0;
}
if( p->pArray ){
Tcl_DecrRefCount(p->pArray);
p->pArray = 0;
if( p->pVarName ){
Tcl_DecrRefCount(p->pVarName);
p->pVarName = 0;
}
Tcl_DecrRefCount(p->pSql);
dbReleaseColumnNames(p);
@@ -1884,7 +1915,7 @@ static int DbUseNre(void){
/*
** This function is part of the implementation of the command:
**
** $db eval SQL ?ARRAYNAME? SCRIPT
** $db eval SQL ?TGT-NAME? SCRIPT
*/
static int SQLITE_TCLAPI DbEvalNextCmd(
ClientData data[], /* data[0] is the (DbEvalContext*) */
@@ -1898,8 +1929,8 @@ static int SQLITE_TCLAPI DbEvalNextCmd(
** is a pointer to a Tcl_Obj containing the script to run for each row
** returned by the queries encapsulated in data[0]. */
DbEvalContext *p = (DbEvalContext *)data[0];
Tcl_Obj *pScript = (Tcl_Obj *)data[1];
Tcl_Obj *pArray = p->pArray;
Tcl_Obj * const pScript = (Tcl_Obj *)data[1];
Tcl_Obj * const pVarName = p->pVarName;
while( (rc==TCL_OK || rc==TCL_CONTINUE) && TCL_OK==(rc = dbEvalStep(p)) ){
int i;
@@ -1907,15 +1938,46 @@ static int SQLITE_TCLAPI DbEvalNextCmd(
Tcl_Obj **apColName;
dbEvalRowInfo(p, &nCol, &apColName);
for(i=0; i<nCol; i++){
if( pArray==0 ){
if( pVarName==0 ){
Tcl_ObjSetVar2(interp, apColName[i], 0, dbEvalColumnValue(p,i), 0);
}else if( (p->evalFlags & SQLITE_EVAL_WITHOUTNULLS)!=0
&& sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
&& sqlite3_column_type(p->pPreStmt->pStmt, i)==SQLITE_NULL
){
Tcl_UnsetVar2(interp, Tcl_GetString(pArray),
Tcl_GetString(apColName[i]), 0);
/* Remove NULL-containing column from the target container... */
if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
/* Target is an array */
Tcl_UnsetVar2(interp, Tcl_GetString(pVarName),
Tcl_GetString(apColName[i]), 0);
}else{
/* Target is a dict */
Tcl_Obj *pDict = Tcl_ObjGetVar2(interp, pVarName, NULL, 0);
if( pDict ){
if( Tcl_IsShared(pDict) ){
pDict = Tcl_DuplicateObj(pDict);
}
if( Tcl_DictObjRemove(interp, pDict, apColName[i])==TCL_OK ){
Tcl_ObjSetVar2(interp, pVarName, NULL, pDict, 0);
}
Tcl_BounceRefCount(pDict);
}
}
}else if( 0==(SQLITE_EVAL_ASDICT & p->evalFlags) ){
/* Target is an array: set target(colName) = colValue */
Tcl_ObjSetVar2(interp, pVarName, apColName[i],
dbEvalColumnValue(p,i), 0);
}else{
Tcl_ObjSetVar2(interp, pArray, apColName[i], dbEvalColumnValue(p,i), 0);
/* Target is a dict: set target(colName) = colValue */
Tcl_Obj *pDict = Tcl_ObjGetVar2(interp, pVarName, NULL, 0);
if( !pDict ){
pDict = Tcl_NewDictObj();
}else if( Tcl_IsShared(pDict) ){
pDict = Tcl_DuplicateObj(pDict);
}
if( Tcl_DictObjPut(interp, pDict, apColName[i],
dbEvalColumnValue(p,i))==TCL_OK ){
Tcl_ObjSetVar2(interp, pVarName, NULL, pDict, 0);
}
Tcl_BounceRefCount(pDict);
}
}
@@ -1987,6 +2049,376 @@ static void DbHookCmd(
sqlite3_wal_hook(db, (pDb->pWalHook?DbWalHandler:0), pDb);
}
/*
** Implementation of the "db format" command.
**
** Based on provided options, format the results of the SQL statement(s)
** provided into human-readable form using the Query Result Formatter (QRF)
** and return the resuling text.
**
** Syntax: db format OPTIONS SQL
**
** OPTIONS may be:
**
** -style ("auto"|"box"|"column"|...) Output style
** -esc ("auto"|"off"|"ascii"|"symbol") How to deal with ctrl chars
** -text ("auto"|"off"|"sql"|"csv"|...) How to escape TEXT values
** -title ("auto"|"off"|"sql"|...|"off") How to escape column names
** -blob ("auto"|"text"|"sql"|...) How to escape BLOB values
** -wordwrap ("auto"|"off"|"on") Try to wrap at word boundry?
** -textjsonb ("auto"|"off"|"on") Auto-convert JSONB to text?
** -splitcolumn ("auto"|"off"|"on") Enable split-column mode
** -defaultalign ("auto"|"left"|...) Default alignment
** -titalalign ("auto"|"left"|"right"|...) Default column name alignment
** -border ("auto"|"off"|"on") Border for box and table styles
** -wrap NUMBER Max width of any single column
** -screenwidth NUMBER Width of the display TTY
** -linelimit NUMBER Max lines for any cell
** -charlimit NUMBER Content truncated to this size
** -titlelimit NUMBER Max width of column titles
** -multiinsert NUMBER Multi-row INSERT byte size
** -align LIST-OF-ALIGNMENT Alignment of columns
** -widths LIST-OF-NUMBERS Widths for individual columns
** -columnsep TEXT Column separator text
** -rowsep TEXT Row separator text
** -tablename TEXT Table name for style "insert"
** -null TEXT Text for NULL values
**
** A mapping from TCL "format" command options to sqlite3_qrf_spec fields
** is below. Use this to reference the QRF documentation:
**
** TCL Option spec field
** ---------- ----------
** -style eStyle
** -esc eEsc
** -text eText
** -title eTitle, bTitle
** -blob eBlob
** -wordwrap bWordWrap
** -textjsonb bTextJsonb
** -splitcolumn bSplitColumn
** -defaultalign eDfltAlign
** -titlealign eTitleAlign
** -border bBorder
** -wrap nWrap
** -screenwidth nScreenWidth
** -linelimit nLineLimit
** -charlimit nCharLimit
** -titlelimit nTitleLimit
** -multiinsert nMultiInsert
** -align nAlign, aAlign
** -widths nWidth, aWidth
** -columnsep zColumnSep
** -rowsep zRowSep
** -tablename zTableName
** -null zNull
*/
static int dbQrf(SqliteDb *pDb, int objc, Tcl_Obj *const*objv){
#ifndef SQLITE_QRF_H
Tcl_SetResult(pDb->interp, "QRF not available in this build", TCL_VOLATILE);
return TCL_ERROR;
#else
char *zResult = 0; /* Result to be returned */
const char *zSql = 0; /* SQL to run */
int i; /* Loop counter */
int rc; /* Result code */
sqlite3_qrf_spec qrf; /* Formatting spec */
static const char *azAlign[] = {
"auto", "bottom", "c",
"center", "e", "left",
"middle", "n", "ne",
"nw", "right", "s",
"se", "sw", "top",
"w", 0
};
static const unsigned char aAlignMap[] = {
QRF_ALIGN_Auto, QRF_ALIGN_Bottom, QRF_ALIGN_C,
QRF_ALIGN_Center, QRF_ALIGN_E, QRF_ALIGN_Left,
QRF_ALIGN_Middle, QRF_ALIGN_N, QRF_ALIGN_NE,
QRF_ALIGN_NW, QRF_ALIGN_Right, QRF_ALIGN_S,
QRF_ALIGN_SE, QRF_ALIGN_SW, QRF_ALIGN_Top,
QRF_ALIGN_W
};
memset(&qrf, 0, sizeof(qrf));
qrf.iVersion = 1;
qrf.pzOutput = &zResult;
for(i=2; i<objc; i++){
const char *zArg = Tcl_GetString(objv[i]);
const char *azBool[] = { "auto", "yes", "no", "on", "off", 0 };
const unsigned char aBoolMap[] = { 0, 2, 1, 2, 1 };
if( zArg[0]!='-' ){
if( zSql ){
Tcl_AppendResult(pDb->interp, "unknown argument: ", zArg, (char*)0);
rc = TCL_ERROR;
goto format_failed;
}
zSql = zArg;
}else if( i==objc-1 ){
Tcl_AppendResult(pDb->interp, "option has no argument: ", zArg, (char*)0);
rc = TCL_ERROR;
goto format_failed;
}else if( strcmp(zArg,"-style")==0 ){
static const char *azStyles[] = {
"auto", "box", "column",
"count", "csv", "eqp",
"explain", "html", "insert",
"jobject", "json", "line",
"list", "markdown", "quote",
"stats", "stats-est", "stats-vm",
"table", 0
};
static unsigned char aStyleMap[] = {
QRF_STYLE_Auto, QRF_STYLE_Box, QRF_STYLE_Column,
QRF_STYLE_Count, QRF_STYLE_Csv, QRF_STYLE_Eqp,
QRF_STYLE_Explain, QRF_STYLE_Html, QRF_STYLE_Insert,
QRF_STYLE_JObject, QRF_STYLE_Json, QRF_STYLE_Line,
QRF_STYLE_List, QRF_STYLE_Markdown, QRF_STYLE_Quote,
QRF_STYLE_Stats, QRF_STYLE_StatsEst, QRF_STYLE_StatsVm,
QRF_STYLE_Table
};
int style;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azStyles,
"format style (-style)", 0, &style);
if( rc ) goto format_failed;
qrf.eStyle = aStyleMap[style];
i++;
}else if( strcmp(zArg,"-esc")==0 ){
static const char *azEsc[] = {
"ascii", "auto", "off", "symbol", 0
};
static unsigned char aEscMap[] = {
QRF_ESC_Ascii, QRF_ESC_Auto, QRF_ESC_Off, QRF_ESC_Symbol
};
int esc;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azEsc,
"control character escape (-esc)", 0, &esc);
if( rc ) goto format_failed;
qrf.eEsc = aEscMap[esc];
i++;
}else if( strcmp(zArg,"-text")==0 || strcmp(zArg, "-title")==0 ){
/* NB: --title can be "off" or "on but --text may not be. Thus we put
** the "off" and "on" choices first and start the search on the
** thrid element of the array when processing --text */
static const char *azText[] = { "off", "on",
"auto", "csv", "html",
"json", "plain", "relaxed",
"sql", "tcl", 0
};
static unsigned char aTextMap[] = {
QRF_TEXT_Auto, QRF_TEXT_Csv, QRF_TEXT_Html,
QRF_TEXT_Json, QRF_TEXT_Plain, QRF_TEXT_Relaxed,
QRF_TEXT_Sql, QRF_TEXT_Tcl
};
int txt;
int k = zArg[2]=='e';
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], &azText[k*2], zArg,
0, &txt);
if( rc ) goto format_failed;
if( k ){
qrf.eText = aTextMap[txt];
}else if( txt<=1 ){
qrf.bTitles = txt ? QRF_Yes : QRF_No;
qrf.eTitle = QRF_TEXT_Auto;
}else{
qrf.bTitles = QRF_Yes;
qrf.eTitle = aTextMap[txt-2];
}
i++;
}else if( strcmp(zArg,"-blob")==0 ){
static const char *azBlob[] = {
"auto", "hex", "json",
"tcl", "text", "sql",
"size", 0
};
static unsigned char aBlobMap[] = {
QRF_BLOB_Auto, QRF_BLOB_Hex, QRF_BLOB_Json,
QRF_BLOB_Tcl, QRF_BLOB_Text, QRF_BLOB_Sql,
QRF_BLOB_Size
};
int blob;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBlob,
"BLOB encoding (-blob)", 0, &blob);
if( rc ) goto format_failed;
qrf.eBlob = aBlobMap[blob];
i++;
}else if( strcmp(zArg,"-wordwrap")==0 ){
int v = 0;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
"-wordwrap", 0, &v);
if( rc ) goto format_failed;
qrf.bWordWrap = aBoolMap[v];
i++;
}else if( strcmp(zArg,"-textjsonb")==0
|| strcmp(zArg,"-splitcolumn")==0
|| strcmp(zArg,"-border")==0
){
int v = 0;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azBool,
zArg, 0, &v);
if( rc ) goto format_failed;
if( zArg[1]=='t' ){
qrf.bTextJsonb = aBoolMap[v];
}else if( zArg[1]=='b' ){
qrf.bBorder = aBoolMap[v];
}else{
qrf.bSplitColumn = aBoolMap[v];
}
i++;
}else if( strcmp(zArg,"-defaultalign")==0 || strcmp(zArg,"-titlealign")==0){
int ax = 0;
rc = Tcl_GetIndexFromObj(pDb->interp, objv[i+1], azAlign,
zArg[1]=='d' ? "default alignment (-defaultalign)" :
"title alignment (-titlealign)",
0, &ax);
if( rc ) goto format_failed;
if( zArg[1]=='d' ){
qrf.eDfltAlign = aAlignMap[ax];
}else{
qrf.eTitleAlign = aAlignMap[ax];
}
i++;
}else if( strcmp(zArg,"-wrap")==0
|| strcmp(zArg,"-screenwidth")==0
|| strcmp(zArg,"-linelimit")==0
|| strcmp(zArg,"-titlelimit")==0
){
int v = 0;
rc = Tcl_GetIntFromObj(pDb->interp, objv[i+1], &v);
if( rc ) goto format_failed;
if( v<QRF_MIN_WIDTH ){
v = QRF_MIN_WIDTH;
}else if( v>QRF_MAX_WIDTH ){
v = QRF_MAX_WIDTH;
}
if( zArg[1]=='w' ){
qrf.nWrap = v;
}else if( zArg[1]=='s' ){
qrf.nScreenWidth = v;
}else if( zArg[1]=='t' ){
qrf.nTitleLimit = v;
}else{
qrf.nLineLimit = v;
}
i++;
}else if( strcmp(zArg,"-charlimit")==0 ){
int v = 0;
rc = Tcl_GetIntFromObj(pDb->interp, objv[i+1], &v);
if( rc ) goto format_failed;
if( v<0 ) v = 0;
qrf.nCharLimit = v;
i++;
}else if( strcmp(zArg,"-multiinsert")==0 ){
int v = 0;
rc = Tcl_GetIntFromObj(pDb->interp, objv[i+1], &v);
if( rc ) goto format_failed;
if( v<0 ) v = 0;
qrf.nMultiInsert = v;
i++;
}else if( strcmp(zArg,"-align")==0 ){
Tcl_Size n = 0;
int jj;
rc = Tcl_ListObjLength(pDb->interp, objv[i+1], &n);
if( rc ) goto format_failed;
sqlite3_free(qrf.aAlign);
qrf.aAlign = sqlite3_malloc64( (n+1)*sizeof(qrf.aAlign[0]) );
if( qrf.aAlign==0 ){
Tcl_AppendResult(pDb->interp, "out of memory", (char*)0);
rc = TCL_ERROR;
goto format_failed;
}
memset(qrf.aAlign, 0, (n+1)*sizeof(qrf.aAlign[0]));
qrf.nAlign = n;
for(jj=0; jj<n; jj++){
int x;
Tcl_Obj *pTerm;
rc = Tcl_ListObjIndex(pDb->interp, objv[i+1], jj, &pTerm);
if( rc ) goto format_failed;
rc = Tcl_GetIndexFromObj(pDb->interp, pTerm, azAlign,
"column alignment (-align)", 0, &x);
if( rc ) goto format_failed;
qrf.aAlign[jj] = aAlignMap[x];
}
i++;
}else if( strcmp(zArg,"-widths")==0 ){
Tcl_Size n = 0;
int jj;
rc = Tcl_ListObjLength(pDb->interp, objv[i+1], &n);
if( rc ) goto format_failed;
sqlite3_free(qrf.aWidth);
qrf.aWidth = sqlite3_malloc64( (n+1)*sizeof(qrf.aWidth[0]) );
if( qrf.aWidth==0 ){
Tcl_AppendResult(pDb->interp, "out of memory", (char*)0);
rc = TCL_ERROR;
goto format_failed;
}
memset(qrf.aWidth, 0, (n+1)*sizeof(qrf.aWidth[0]));
qrf.nWidth = n;
for(jj=0; jj<n; jj++){
Tcl_Obj *pTerm;
int v;
rc = Tcl_ListObjIndex(pDb->interp, objv[i+1], jj, &pTerm);
if( rc ) goto format_failed;
rc = Tcl_GetIntFromObj(pDb->interp, pTerm, &v);
if( v<(-QRF_MAX_WIDTH) ){
v = -QRF_MAX_WIDTH;
}else if( v>QRF_MAX_WIDTH ){
v = QRF_MAX_WIDTH;
}
qrf.aWidth[jj] = (short int)v;
}
i++;
}else if( strcmp(zArg,"-columnsep")==0 ){
qrf.zColumnSep = Tcl_GetString(objv[i+1]);
i++;
}else if( strcmp(zArg,"-rowsep")==0 ){
qrf.zRowSep = Tcl_GetString(objv[i+1]);
i++;
}else if( strcmp(zArg,"-tablename")==0 ){
qrf.zTableName = Tcl_GetString(objv[i+1]);
i++;
}else if( strcmp(zArg,"-null")==0 ){
qrf.zNull = Tcl_GetString(objv[i+1]);
i++;
}else if( strcmp(zArg,"-version")==0 ){
/* Undocumented. Testing use only */
qrf.iVersion = atoi(Tcl_GetString(objv[i+1]));
i++;
}else{
Tcl_AppendResult(pDb->interp, "unknown option: ", zArg, (char*)0);
rc = TCL_ERROR;
goto format_failed;
}
}
while( zSql && zSql[0] ){
SqlPreparedStmt *pStmt = 0; /* Next statement to run */
char *zErr = 0; /* Error message from QRF */
rc = dbPrepareAndBind(pDb, zSql, &zSql, &pStmt);
if( rc ) goto format_failed;
if( pStmt==0 ) continue;
rc = sqlite3_format_query_result(pStmt->pStmt, &qrf, &zErr);
dbReleaseStmt(pDb, pStmt, 0);
if( rc ){
Tcl_SetResult(pDb->interp, zErr, TCL_VOLATILE);
sqlite3_free(zErr);
rc = TCL_ERROR;
goto format_failed;
}
}
Tcl_SetResult(pDb->interp, zResult, TCL_VOLATILE);
rc = TCL_OK;
/* Fall through...*/
format_failed:
sqlite3_free(qrf.aWidth);
sqlite3_free(qrf.aAlign);
sqlite3_free(zResult);
return rc;
#endif
}
/*
** The "sqlite" command below creates a new Tcl command for each
** connection it opens to an SQLite database. This routine is invoked
@@ -2016,15 +2448,15 @@ static int SQLITE_TCLAPI DbObjCmd(
"commit_hook", "complete", "config",
"copy", "deserialize", "enable_load_extension",
"errorcode", "erroroffset", "eval",
"exists", "function", "incrblob",
"interrupt", "last_insert_rowid", "nullvalue",
"onecolumn", "preupdate", "profile",
"progress", "rekey", "restore",
"rollback_hook", "serialize", "status",
"timeout", "total_changes", "trace",
"trace_v2", "transaction", "unlock_notify",
"update_hook", "version", "wal_hook",
0
"exists", "format", "function",
"incrblob", "interrupt", "last_insert_rowid",
"nullvalue", "onecolumn", "preupdate",
"profile", "progress", "rekey",
"restore", "rollback_hook", "serialize",
"status", "timeout", "total_changes",
"trace", "trace_v2", "transaction",
"unlock_notify", "update_hook", "version",
"wal_hook", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BIND_FALLBACK,
@@ -2033,14 +2465,15 @@ static int SQLITE_TCLAPI DbObjCmd(
DB_COMMIT_HOOK, DB_COMPLETE, DB_CONFIG,
DB_COPY, DB_DESERIALIZE, DB_ENABLE_LOAD_EXTENSION,
DB_ERRORCODE, DB_ERROROFFSET, DB_EVAL,
DB_EXISTS, DB_FUNCTION, DB_INCRBLOB,
DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE,
DB_ONECOLUMN, DB_PREUPDATE, DB_PROFILE,
DB_PROGRESS, DB_REKEY, DB_RESTORE,
DB_ROLLBACK_HOOK, DB_SERIALIZE, DB_STATUS,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_TRACE_V2, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
DB_EXISTS, DB_FORMAT, DB_FUNCTION,
DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID,
DB_NULLVALUE, DB_ONECOLUMN, DB_PREUPDATE,
DB_PROFILE, DB_PROGRESS, DB_REKEY,
DB_RESTORE, DB_ROLLBACK_HOOK, DB_SERIALIZE,
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
DB_WAL_HOOK
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -2858,13 +3291,15 @@ deserialize_error:
}
/*
** $db eval ?options? $sql ?array? ?{ ...code... }?
** $db eval ?options? $sql ?varName? ?{ ...code... }?
**
** The SQL statement in $sql is evaluated. For each row, the values are
** placed in elements of the array named "array" and ...code... is executed.
** If "array" and "code" are omitted, then no callback is every invoked.
** If "array" is an empty string, then the values are placed in variables
** that have the same name as the fields extracted by the query.
** The SQL statement in $sql is evaluated. For each row, the values
** are placed in elements of the array or dict named $varName and
** ...code... is executed. If $varName and $code are omitted, then
** no callback is ever invoked. If $varName is an empty string,
** then the values are placed in variables that have the same name
** as the fields extracted by the query, and those variables are
** accessible during the eval of $code.
*/
case DB_EVAL: {
int evalFlags = 0;
@@ -2872,8 +3307,9 @@ deserialize_error:
while( objc>3 && (zOpt = Tcl_GetString(objv[2]))!=0 && zOpt[0]=='-' ){
if( strcmp(zOpt, "-withoutnulls")==0 ){
evalFlags |= SQLITE_EVAL_WITHOUTNULLS;
}
else{
}else if( strcmp(zOpt, "-asdict")==0 ){
evalFlags |= SQLITE_EVAL_ASDICT;
}else{
Tcl_AppendResult(interp, "unknown option: \"", zOpt, "\"", (void*)0);
return TCL_ERROR;
}
@@ -2881,8 +3317,8 @@ deserialize_error:
objv++;
}
if( objc<3 || objc>5 ){
Tcl_WrongNumArgs(interp, 2, objv,
"?OPTIONS? SQL ?ARRAY-NAME? ?SCRIPT?");
Tcl_WrongNumArgs(interp, 2, objv,
"?OPTIONS? SQL ?VAR-NAME? ?SCRIPT?");
return TCL_ERROR;
}
@@ -2908,17 +3344,17 @@ deserialize_error:
}else{
ClientData cd2[2];
DbEvalContext *p;
Tcl_Obj *pArray = 0;
Tcl_Obj *pVarName = 0;
Tcl_Obj *pScript;
if( objc>=5 && *(char *)Tcl_GetString(objv[3]) ){
pArray = objv[3];
pVarName = objv[3];
}
pScript = objv[objc-1];
Tcl_IncrRefCount(pScript);
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
dbEvalInit(p, pDb, objv[2], pArray, evalFlags);
dbEvalInit(p, pDb, objv[2], pVarName, evalFlags);
cd2[0] = (void *)p;
cd2[1] = (void *)pScript;
@@ -2927,6 +3363,18 @@ deserialize_error:
break;
}
/*
** $db format [OPTIONS] SQL
**
** Run the SQL statement(s) given as the final argument. Use the
** Query Result Formatter extension of SQLite to format the output as
** text and return that text.
*/
case DB_FORMAT: {
rc = dbQrf(pDb, objc, objv);
break;
}
/*
** $db function NAME [OPTIONS] SCRIPT
**
+7 -3
View File
@@ -64,12 +64,18 @@ apply {{dir} {
-name.pkg sqlite3
-version $version
-name.dist $distname
-vsatisfies 8.6-
-libDir sqlite$version
-pragmas $pragmas
-src generic/tclsqlite3.c
}
# We should also have:
# -vsatisfies 8.6-
# But at least one platform is failing this vsatisfies check
# for no apparent reason:
# https://sqlite.org/forum/forumpost/fde857fb8101a4be
}} [teaish-get -dir]
#
# Must return either an empty string or a list in the form accepted by
# autosetup's [options] function.
@@ -119,8 +125,6 @@ proc teaish-options {} {
proc teaish-configure {} {
use teaish/feature
teaish-src-add -dist -dir generic/tclsqlite3.c
if {[proj-opt-was-provided override-sqlite-version]} {
teaish-pkginfo-set -version [opt-val override-sqlite-version]
proj-warn "overriding sqlite version number:" [teaish-pkginfo-get -version]