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:
+7
-4
@@ -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
@@ -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)
|
||||
|
||||
+15
-4
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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]
|
||||
|
||||
Vendored
+15
-2
@@ -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" \
|
||||
"$@"
|
||||
|
||||
@@ -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
@@ -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
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user