Fossil SCM

Merge from trunk

brickviking 2025-02-26 20:14 UTC bv-infotool merge
Commit 17efadc96f05895b816fb7b31d56ef672a27b37a8fa626302af58907b2c86e65
--- Makefile.classic
+++ Makefile.classic
@@ -95,11 +95,11 @@
9595
#
9696
# Automatic platform-specific options.
9797
HOST_OS_CMD = uname -s
9898
HOST_OS = $(HOST_OS_CMD:sh)
9999
100
-LIB.SunOS= -lsocket -lnsl
100
+LIB.SunOS= -lsocket -lnsl -lrt
101101
LIB += $(LIB.$(HOST_OS))
102102
103103
TCC.DragonFly += -DUSE_PREAD
104104
TCC.FreeBSD += -DUSE_PREAD
105105
TCC.NetBSD += -DUSE_PREAD
106106
--- Makefile.classic
+++ Makefile.classic
@@ -95,11 +95,11 @@
95 #
96 # Automatic platform-specific options.
97 HOST_OS_CMD = uname -s
98 HOST_OS = $(HOST_OS_CMD:sh)
99
100 LIB.SunOS= -lsocket -lnsl
101 LIB += $(LIB.$(HOST_OS))
102
103 TCC.DragonFly += -DUSE_PREAD
104 TCC.FreeBSD += -DUSE_PREAD
105 TCC.NetBSD += -DUSE_PREAD
106
--- Makefile.classic
+++ Makefile.classic
@@ -95,11 +95,11 @@
95 #
96 # Automatic platform-specific options.
97 HOST_OS_CMD = uname -s
98 HOST_OS = $(HOST_OS_CMD:sh)
99
100 LIB.SunOS= -lsocket -lnsl -lrt
101 LIB += $(LIB.$(HOST_OS))
102
103 TCC.DragonFly += -DUSE_PREAD
104 TCC.FreeBSD += -DUSE_PREAD
105 TCC.NetBSD += -DUSE_PREAD
106
+656 -542
--- auto.def
+++ auto.def
@@ -41,12 +41,26 @@
4141
define MINIMUM_SQLITE_VERSION "3.46.0"
4242
4343
# This is useful for people wanting Fossil to use an external SQLite library
4444
# to compare the one they have against the minimum required
4545
if {[opt-bool print-minimum-sqlite-version]} {
46
- puts [get-define MINIMUM_SQLITE_VERSION]
47
- exit 0
46
+ puts [get-define MINIMUM_SQLITE_VERSION]
47
+ exit 0
48
+}
49
+
50
+# Space characters have never been allowed in either the source
51
+# tree nor the build directory. But the resulting error messages
52
+# could be confusing. The following checks make the reason for the
53
+# failure clear.
54
+#
55
+if {[string first " " $autosetup(srcdir)] != -1} {
56
+ user-error "The pathname of the source tree\
57
+ may not contain space characters"
58
+}
59
+if {[string first " " $autosetup(builddir)] != -1} {
60
+ user-error "The pathname of the build directory\
61
+ may not contain space characters"
4862
}
4963
5064
set outOfTreeBuild 0
5165
if {![file exists fossil.1]} {
5266
puts "This appears to be an out-of-tree build."
@@ -53,21 +67,21 @@
5367
set outOfTreeBuild 1
5468
}
5569
5670
# sqlite wants these types if possible
5771
cc-with {-includes {stdint.h inttypes.h}} {
58
- cc-check-types uint32_t uint16_t int16_t uint8_t
72
+ cc-check-types uint32_t uint16_t int16_t uint8_t
5973
}
6074
6175
# Use pread/pwrite system calls in place of seek + read/write if possible
6276
define USE_PREAD [cc-check-functions pread]
6377
6478
# If we have cscope here, we'll use it in the "tags" target
6579
if {[cc-check-progs cscope]} {
66
- define COLLECT_CSCOPE_DATA "cscope -bR $::autosetup(srcdir)/src/*.\[ch\]"
80
+ define COLLECT_CSCOPE_DATA "cscope -bR $::autosetup(srcdir)/src/*.\[ch\]"
6781
} else {
68
- define COLLECT_CSCOPE_DATA ""
82
+ define COLLECT_CSCOPE_DATA ""
6983
}
7084
7185
# Find tclsh for the test suite.
7286
#
7387
# We can't use jimsh for this: the test suite uses features of Tcl that
@@ -80,35 +94,35 @@
8094
# Ironically, this means we may right now be running under either jimsh0
8195
# or a version of tclsh that we find unsuitable below!
8296
cc-check-progs tclsh
8397
set hbtd /usr/local/Cellar/tcl-tk
8498
if {[string equal false [get-define TCLSH]]} {
85
- msg-result "WARNING: 'make test' will not run here."
86
-} else {
87
- set v [exec /bin/sh -c "echo 'puts \$tcl_version' | tclsh"]
88
- if {[expr {$v >= 8.6}]} {
89
- msg-result "Found Tclsh version $v in the PATH."
90
- define TCLSH tclsh
91
- } elseif {[file isdirectory $hbtd]} {
92
- # This is a macOS system with the Homebrew version of Tcl/Tk
93
- # installed. Select the newest version. It won't normally be
94
- # in the PATH to avoid shadowing /usr/bin/tclsh, and even if it
95
- # were in the PATH, it's bad practice to put /usr/local/bin (the
96
- # Homebrew default) ahead of /usr/bin, especially given that
97
- # it's user-writeable by default with Homebrew. Thus, we can be
98
- # pretty sure the only way to call it is with an absolute path.
99
- set v [exec ls -tr $hbtd | tail -1]
100
- set path "$hbtd/$v/bin/tclsh"
101
- define TCLSH $path
102
- msg-result "Using Homebrew Tcl/Tk version $path."
103
- } else {
104
- msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
105
- define TCLSH false ;# force "make test" failure via /usr/bin/false
106
- }
107
-}
108
-
109
-define CFLAGS [get-env CFLAGS "-g -O2"]
99
+ msg-result "WARNING: 'make test' will not run here."
100
+} else {
101
+ set v [exec sh -c "echo 'puts \$tcl_version' | tclsh"]
102
+ if {[expr {$v >= 8.6}]} {
103
+ msg-result "Found Tclsh version $v in the PATH."
104
+ define TCLSH tclsh
105
+ } elseif {[file isdirectory $hbtd]} {
106
+ # This is a macOS system with the Homebrew version of Tcl/Tk
107
+ # installed. Select the newest version. It won't normally be
108
+ # in the PATH to avoid shadowing /usr/bin/tclsh, and even if it
109
+ # were in the PATH, it's bad practice to put /usr/local/bin (the
110
+ # Homebrew default) ahead of /usr/bin, especially given that
111
+ # it's user-writeable by default with Homebrew. Thus, we can be
112
+ # pretty sure the only way to call it is with an absolute path.
113
+ set v [exec ls -tr $hbtd | tail -1]
114
+ set path "$hbtd/$v/bin/tclsh"
115
+ define TCLSH $path
116
+ msg-result "Using Homebrew Tcl/Tk version $path."
117
+ } else {
118
+ msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
119
+ define TCLSH false ;# force "make test" failure via /usr/bin/false
120
+ }
121
+}
122
+
123
+define CFLAGS [get-env CFLAGS "-g -Os"]
110124
define EXTRA_CFLAGS "-Wall"
111125
define EXTRA_LDFLAGS ""
112126
define USE_SYSTEM_SQLITE 0
113127
define USE_LINENOISE 0
114128
define USE_MMAN_H 0
@@ -119,48 +133,48 @@
119133
# SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
120134
121135
# Maintain the C89/C90-style order of variable declarations before statements.
122136
# Check if the compiler supports the respective warning flag.
123137
if {[cctest -cflags -Wdeclaration-after-statement]} {
124
- define-append EXTRA_CFLAGS -Wdeclaration-after-statement
138
+ define-append EXTRA_CFLAGS -Wdeclaration-after-statement
125139
}
126140
127141
128142
# This procedure is a customized version of "cc-check-function-in-lib",
129143
# that does not modify the LIBS variable. Its use prevents prematurely
130144
# pulling in libraries that will be added later anyhow (e.g. "-ldl").
131145
proc check-function-in-lib {function libs {otherlibs {}}} {
132
- if {[string length $otherlibs]} {
133
- msg-checking "Checking for $function in $libs with $otherlibs..."
134
- } else {
135
- msg-checking "Checking for $function in $libs..."
136
- }
137
- set found 0
138
- cc-with [list -libs $otherlibs] {
139
- if {[cctest_function $function]} {
140
- msg-result "none needed"
141
- define lib_$function ""
142
- incr found
143
- } else {
144
- foreach lib $libs {
145
- cc-with [list -libs -l$lib] {
146
- if {[cctest_function $function]} {
147
- msg-result -l$lib
148
- define lib_$function -l$lib
149
- incr found
150
- break
151
- }
152
- }
153
- }
154
- }
155
- }
156
- if {$found} {
157
- define [feature-define-name $function]
158
- } else {
159
- msg-result "no"
160
- }
161
- return $found
146
+ if {[string length $otherlibs]} {
147
+ msg-checking "Checking for $function in $libs with $otherlibs..."
148
+ } else {
149
+ msg-checking "Checking for $function in $libs..."
150
+ }
151
+ set found 0
152
+ cc-with [list -libs $otherlibs] {
153
+ if {[cctest_function $function]} {
154
+ msg-result "none needed"
155
+ define lib_$function ""
156
+ incr found
157
+ } else {
158
+ foreach lib $libs {
159
+ cc-with [list -libs -l$lib] {
160
+ if {[cctest_function $function]} {
161
+ msg-result -l$lib
162
+ define lib_$function -l$lib
163
+ incr found
164
+ break
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ if {$found} {
171
+ define [feature-define-name $function]
172
+ } else {
173
+ msg-result "no"
174
+ }
175
+ return $found
162176
}
163177
164178
if {![opt-bool internal-sqlite]} {
165179
proc find_system_sqlite {} {
166180
@@ -205,17 +219,17 @@
205219
set sqlite-version [string cat "-D MINIMUM_SQLITE_VERSION=" [get-define MINIMUM_SQLITE_VERSION]]
206220
lappend cmdline {*}[set sqlite-version]
207221
set ok 1
208222
set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
209223
if {$err} {
210
- configlog "Failed: [join $cmdline]"
211
- if {[string length $result]>0} {configlog $result}
212
- configlog "============"
213
- set ok 0
224
+ configlog "Failed: [join $cmdline]"
225
+ if {[string length $result]>0} {configlog $result}
226
+ configlog "============"
227
+ set ok 0
214228
} elseif {$::autosetup(debug)} {
215
- configlog "Compiled OK: [join $cmdline]"
216
- configlog "============"
229
+ configlog "Compiled OK: [join $cmdline]"
230
+ configlog "============"
217231
}
218232
if {!$ok} {
219233
user-error "unable to compile SQLite compatibility test program"
220234
}
221235
set err [catch {exec-with-stderr ./conftest__} result errinfo]
@@ -230,498 +244,525 @@
230244
test_system_sqlite
231245
232246
}
233247
234248
proc is_mingw {} {
235
- return [string match *mingw* [get-define host]]
236
-}
237
-
238
-if {[is_mingw]} {
239
- define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
240
- define-append LIBS -lkernel32 -lws2_32
241
-} else {
242
- #
243
- # NOTE: All platforms except MinGW should use the linenoise
244
- # package. It is currently unsupported on Win32.
245
- #
246
- define USE_LINENOISE 1
247
-}
248
-
249
-if {[string match *-solaris* [get-define host]]} {
250
- define-append EXTRA_CFLAGS {-D__EXTENSIONS__}
251
-}
252
-
253
-if {[opt-bool fossil-debug]} {
254
- define CFLAGS {-g -O0 -Wall}
255
- define-append CFLAGS -DFOSSIL_DEBUG
256
- msg-result "Debugging support enabled"
257
-}
258
-
259
-if {[opt-bool no-opt]} {
260
- define CFLAGS {-g -O0 -Wall}
261
- msg-result "Builting without compiler optimization"
262
- if {[opt-bool fossil-debug]} {
263
- define-append CFLAGS -DFOSSIL_DEBUG
264
- }
265
-}
266
-
267
-if {[opt-bool with-mman]} {
268
- define-append EXTRA_CFLAGS -DUSE_MMAN_H
269
- define USE_MMAN_H 1
270
- msg-result "Enabling \"sys/mman.h\" support"
249
+ return [expr {
250
+ [string match *mingw* [get-define host]] &&
251
+ ![file exists "/dev/null"]
252
+ }]
253
+}
254
+
255
+if {[is_mingw]} {
256
+ define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
257
+ define-append LIBS -lkernel32 -lws2_32
258
+} else {
259
+ #
260
+ # NOTE: All platforms except MinGW should use the linenoise
261
+ # package. It is currently unsupported on Win32.
262
+ #
263
+ define USE_LINENOISE 1
264
+}
265
+
266
+if {[string match *-solaris* [get-define host]]} {
267
+ define-append EXTRA_CFLAGS {-D__EXTENSIONS__}
268
+}
269
+
270
+if {[opt-bool fossil-debug]} {
271
+ define CFLAGS {-g -O0 -Wall}
272
+ define-append CFLAGS -DFOSSIL_DEBUG
273
+ msg-result "Debugging support enabled"
274
+}
275
+
276
+if {[opt-bool no-opt]} {
277
+ define CFLAGS {-g -O0 -Wall}
278
+ msg-result "Builting without compiler optimization"
279
+ if {[opt-bool fossil-debug]} {
280
+ define-append CFLAGS -DFOSSIL_DEBUG
281
+ }
282
+}
283
+
284
+if {[opt-bool with-mman]} {
285
+ define-append EXTRA_CFLAGS -DUSE_MMAN_H
286
+ define USE_MMAN_H 1
287
+ msg-result "Enabling \"sys/mman.h\" support"
271288
}
272289
273290
if {[opt-bool with-see]} {
274
- define-append EXTRA_CFLAGS -DUSE_SEE
275
- define USE_SEE 1
276
- define SQLITE3_ORIGIN 1
277
- msg-result "Enabling encryption support"
291
+ define-append EXTRA_CFLAGS -DUSE_SEE
292
+ define USE_SEE 1
293
+ define SQLITE3_ORIGIN 1
294
+ msg-result "Enabling encryption support"
278295
}
279296
280297
if {[opt-bool json]} {
281
- # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
282
- # is required in the CFLAGS because json*.c
283
- # have #ifdef guards around the whole file without
284
- # reading config.h first.
285
- define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
286
- define FOSSIL_ENABLE_JSON
287
- msg-result "JSON support enabled"
298
+ # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
299
+ # is required in the CFLAGS because json*.c
300
+ # have #ifdef guards around the whole file without
301
+ # reading config.h first.
302
+ define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
303
+ define FOSSIL_ENABLE_JSON
304
+ msg-result "JSON support enabled"
288305
}
289306
290307
if {[opt-bool with-exec-rel-paths]} {
291
- define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS
292
- define FOSSIL_ENABLE_EXEC_REL_PATHS
293
- msg-result "Relative paths in external diff/gdiff enabled"
308
+ define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS
309
+ define FOSSIL_ENABLE_EXEC_REL_PATHS
310
+ msg-result "Relative paths in external diff/gdiff enabled"
294311
}
295312
296313
if {[opt-bool with-th1-docs]} {
297
- define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS
298
- define FOSSIL_ENABLE_TH1_DOCS
299
- msg-result "TH1 embedded documentation support enabled"
314
+ define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS
315
+ define FOSSIL_ENABLE_TH1_DOCS
316
+ msg-result "TH1 embedded documentation support enabled"
300317
}
301318
302319
if {[opt-bool with-th1-hooks]} {
303
- define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS
304
- define FOSSIL_ENABLE_TH1_HOOKS
305
- msg-result "TH1 hooks support enabled"
320
+ define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS
321
+ define FOSSIL_ENABLE_TH1_HOOKS
322
+ msg-result "TH1 hooks support enabled"
306323
}
307324
308325
#if {[opt-bool markdown]} {
309326
# # no-op. Markdown is now enabled by default.
310327
# msg-result "Markdown support enabled"
311328
#}
312329
313330
if {[opt-bool static]} {
314
- # XXX: This will not work on all systems.
315
- define-append EXTRA_LDFLAGS -static
316
- msg-result "Trying to link statically"
331
+ # XXX: This will not work on all systems.
332
+ define-append EXTRA_LDFLAGS -static
333
+ msg-result "Trying to link statically"
317334
} else {
318
- define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
319
- define FOSSIL_DYNAMIC_BUILD
335
+ define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
336
+ define FOSSIL_DYNAMIC_BUILD
320337
}
321338
322339
# Check for libraries that need to be sorted out early
323340
cc-check-function-in-lib iconv iconv
324341
342
+cc-check-function-in-lib sin m ;# must come before ssl check:
343
+ # https://fossil-scm.org/forum/forumpost/afcd42b7fd
344
+
325345
# Helper for OpenSSL checking
326346
proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto -lpthread}}} {
327
- msg-checking "Checking for $msg..."
328
- set rc 0
329
- if {[is_mingw]} {
330
- lappend libs -lgdi32 -lwsock32 -lcrypt32
331
- }
332
- if {[info exists ::zlib_lib]} {
333
- lappend libs $::zlib_lib
334
- }
335
- msg-quiet cc-with [list -cflags $cflags -libs $libs] {
336
- if {[cc-check-includes openssl/ssl.h] && \
337
- [cc-check-functions SSL_new]} {
338
- incr rc
339
- }
340
- }
341
- if {!$rc && ![is_mingw]} {
342
- # On some systems, OpenSSL appears to require -ldl to link.
343
- lappend libs -ldl
344
- msg-quiet cc-with [list -cflags $cflags -libs $libs] {
345
- if {[cc-check-includes openssl/ssl.h] && \
346
- [cc-check-functions SSL_new]} {
347
- incr rc
348
- }
349
- }
350
- }
351
- if {$rc} {
352
- msg-result "ok"
353
- return 1
354
- } else {
355
- msg-result "no"
356
- return 0
357
- }
358
-}
359
-
347
+ msg-checking "Checking for $msg..."
348
+ set rc 0
349
+ if {[is_mingw]} {
350
+ lappend libs -lgdi32 -lwsock32 -lcrypt32
351
+ }
352
+ if {[info exists ::zlib_lib]} {
353
+ lappend libs $::zlib_lib
354
+ }
355
+ msg-quiet cc-with [list -cflags $cflags -libs $libs] {
356
+ if {[cc-check-includes openssl/ssl.h] && \
357
+ [cc-check-functions SSL_new]} {
358
+ incr rc
359
+ }
360
+ }
361
+ if {!$rc && ![is_mingw]} {
362
+ # On some systems, OpenSSL appears to require -ldl to link.
363
+ lappend libs -ldl
364
+ msg-quiet cc-with [list -cflags $cflags -libs $libs] {
365
+ if {[cc-check-includes openssl/ssl.h] && \
366
+ [cc-check-functions SSL_new]} {
367
+ incr rc
368
+ }
369
+ }
370
+ }
371
+ if {$rc} {
372
+ msg-result "ok"
373
+ return 1
374
+ } else {
375
+ msg-result "no"
376
+ return 0
377
+ }
378
+}
379
+
380
+#
360381
# Check for zlib, using the given location if specified
361
-set zlibpath [opt-val with-zlib]
362
-if {$zlibpath eq "tree"} {
363
- set zlibdir [file dirname $autosetup(dir)]/compat/zlib
364
- if {![file isdirectory $zlibdir]} {
365
- user-error "The zlib in source tree directory does not exist"
366
- } elseif { ([llength [glob -nocomplain -directory $zlibdir libz*]] == 0) } {
367
- user-error "With --with-zlib=tree, $zlibdir must be configured and built first."
368
- }
369
- cc-with [list -cflags "-I$zlibdir -L$zlibdir"]
370
- define-append EXTRA_CFLAGS -I$zlibdir
371
- define-append LIBS $zlibdir/libz.a
372
- set ::zlib_lib $zlibdir/libz.a
373
- msg-result "Using zlib in source tree"
374
-} else {
375
- set cftry {""}
376
- set ldtry {""}
377
- if {$zlibpath ni {auto ""}} {
378
- lappend cftry "-I$zlibpath"
379
- lappend cftry "-I$zlibpath/include"
380
- lappend ldtry "-L$zlibpath"
381
- lappend ldtry "-L$zlibpath/lib"
382
- }
383
-
384
- # Reverse the list of tests so we check most-specific to least, else
385
- # platform devel files will shadow local --with-zlib overrides.
386
- foreach c [lreverse $cftry] {
387
- if {[cc-with [list -cflags $c] {cc-check-includes zlib.h}]} {
388
- if {$c eq ""} {
389
- msg-result "Found zlib.h in default include path"
390
- } else {
391
- define-append EXTRA_CFLAGS "$c"
392
- msg-result "Found zlib.h via $c"
393
- }
394
- set cfound $c
395
- break
396
- }
397
- }
398
- if {![info exists cfound]} {
399
- user-error "zlib.h not found; either install it or specify its location via --with-zlib"
400
- }
401
- foreach lcheck [lreverse $ldtry] {
402
- if {[cc-with [list -cflags "$cfound $lcheck"] {check-function-in-lib inflateEnd z}]} {
403
- if {$lcheck eq ""} {
404
- msg-result "Linked to zlib via default library path"
405
- } else {
406
- define-append EXTRA_LDFLAGS "$lcheck"
407
- msg-result "Linked to zlib via $lcheck"
408
- }
409
- if {![check-function-in-lib compressBound z]} {
410
- puts "Notice: disabling zlib compression in the SQL shell"
411
- define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
412
- }
413
- break
414
- }
415
- }
416
- set ::zlib_lib -lz
417
-}
418
-
419
-set ssldirs [opt-val with-openssl]
420
-if {$ssldirs ne "none"} {
382
+#
383
+proc handle-zlib {} {
384
+ set ::zlibpath [opt-val with-zlib]; # used by downstream tcl tests
385
+ if {$::zlibpath eq "tree"} {
386
+ set ::zlibdir [file dirname $::autosetup(dir)]/compat/zlib
387
+ if {![file isdirectory $::zlibdir]} {
388
+ user-error "The zlib in source tree directory does not exist"
389
+ } elseif { ([llength [glob -nocomplain -directory $::zlibdir libz*]] == 0) } {
390
+ user-error "With --with-zlib=tree, $::zlibdir must be configured and built first."
391
+ }
392
+ cc-with [list -cflags "-I$::zlibdir -L$::zlibdir"]
393
+ define-append EXTRA_CFLAGS -I$::zlibdir
394
+ define-append LIBS $::zlibdir/libz.a
395
+ set ::zlib_lib $::zlibdir/libz.a
396
+ msg-result "Using zlib in source tree"
397
+ } else {
398
+ set cftry {""}
399
+ set ldtry {""}
400
+ if {$::zlibpath ni {auto ""}} {
401
+ lappend cftry "-I$::zlibpath"
402
+ lappend cftry "-I$::zlibpath/include"
403
+ lappend ldtry "-L$::zlibpath"
404
+ lappend ldtry "-L$::zlibpath/lib"
405
+ }
406
+
407
+ # Reverse the list of tests so we check most-specific to least, else
408
+ # platform devel files will shadow local --with-zlib overrides.
409
+ foreach c [lreverse $cftry] {
410
+ if {[cc-with [list -cflags $c] {cc-check-includes zlib.h}]} {
411
+ if {$c eq ""} {
412
+ msg-result "Found zlib.h in default include path"
413
+ } else {
414
+ define-append EXTRA_CFLAGS "$c"
415
+ msg-result "Found zlib.h via $c"
416
+ }
417
+ set cfound $c
418
+ break
419
+ }
420
+ }
421
+ if {![info exists cfound]} {
422
+ user-error "zlib.h not found; either install it or specify its location via --with-zlib"
423
+ }
424
+ foreach lcheck [lreverse $ldtry] {
425
+ if {[cc-with [list -cflags "$cfound $lcheck"] {check-function-in-lib inflateEnd z}]} {
426
+ if {$lcheck eq ""} {
427
+ msg-result "Linked to zlib via default library path"
428
+ } else {
429
+ define-append EXTRA_LDFLAGS "$lcheck"
430
+ msg-result "Linked to zlib via $lcheck"
431
+ }
432
+ if {![check-function-in-lib compressBound z]} {
433
+ puts "Notice: disabling zlib compression in the SQL shell"
434
+ define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
435
+ }
436
+ break
437
+ }
438
+ }
439
+ set ::zlib_lib -lz
440
+ }
441
+}; # handle-zlib
442
+handle-zlib
443
+
444
+#
445
+# Handle the --with-openssl flag and, incidentally, update @LIBS@ for
446
+# zlib if openssl is _not_ used (if it is, we get zlib via libssl).
447
+#
448
+# This function should be called as late as possible in the configure
449
+# script to avoid that its updates to @LIBS@ break tests which follow
450
+# it when a custom local build of openssl is used, as discussed in
451
+# <https://fossil-scm.org/forum/forumpost/15e3d9cdc137030c>.
452
+#
453
+proc handle-with-openssl {} {
454
+ set ssldirs [opt-val with-openssl]
455
+ if {$ssldirs ne "none"} {
421456
set found 0
422457
if {$ssldirs eq "tree"} {
423
- set ssldir [file dirname $autosetup(dir)]/compat/openssl
424
- if {![file isdirectory $ssldir]} {
425
- user-error "The OpenSSL in source tree directory does not exist"
426
- }
427
- set msg "ssl in $ssldir"
428
- set cflags "-I$ssldir/include"
429
- set ldflags "-L$ssldir"
430
- set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
431
- set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
458
+ set ssldir [file dirname $::autosetup(dir)]/compat/openssl
459
+ if {![file isdirectory $ssldir]} {
460
+ user-error "The OpenSSL in source tree directory does not exist"
461
+ }
462
+ set msg "openssl in $ssldir"
463
+ set cflags "-I$ssldir/include"
464
+ set ldflags "-L$ssldir"
465
+ set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
466
+ set found [check-for-openssl "openssl in source tree" "$cflags $ldflags" $ssllibs]
432467
} else {
433
- if {$ssldirs in {auto ""}} {
434
- catch {
435
- set cflags [exec pkg-config openssl --cflags-only-I]
436
- set ldflags [exec pkg-config openssl --libs-only-L]
437
- set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
438
- } msg
439
- if {!$found} {
440
- set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \
468
+ if {$ssldirs in {auto ""}} {
469
+ catch {
470
+ # TODO?: use autosetup's pkg-config support
471
+ set cflags [exec pkg-config openssl --cflags-only-I]
472
+ set ldflags [exec pkg-config openssl --libs-only-L]
473
+ set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
474
+ } msg
475
+ if {!$found} {
476
+ set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \
441477
/usr/pkg /usr/local /usr /usr/local/opt/openssl \
442478
/opt/homebrew/opt/openssl"
443
- }
444
- }
445
- if {!$found} {
446
- foreach dir $ssldirs {
447
- if {$dir eq ""} {
448
- set msg "system ssl"
449
- set cflags ""
450
- set ldflags ""
451
- } else {
452
- set msg "ssl in $dir"
453
- set cflags "-I$dir/include"
454
- set ldflags "-L$dir/lib"
455
- }
456
- if {[check-for-openssl $msg "$cflags $ldflags"]} {
457
- incr found
458
- break
459
- }
460
- }
461
- }
479
+ }
480
+ }
481
+ if {!$found} {
482
+ foreach dir $ssldirs {
483
+ if {$dir eq ""} {
484
+ set msg "system openssl"
485
+ set cflags ""
486
+ set ldflags ""
487
+ } else {
488
+ set msg "openssl in $dir"
489
+ set cflags "-I$dir/include"
490
+ if {[file readable $dir/libssl.a]} {
491
+ set ldflags -L$dir
492
+ } elseif {[file readable $dir/lib/libssl.a]} {
493
+ set ldflags -L$dir/lib
494
+ } elseif {[file isdir $dir/lib]} {
495
+ set ldflags "-L$dir -L$dir/lib"
496
+ } else {
497
+ set ldflags -L$dir
498
+ }
499
+ }
500
+ if {[check-for-openssl $msg "$cflags $ldflags"]} {
501
+ incr found
502
+ break
503
+ }
504
+ if {$dir ne ""} {
505
+ set ldflags ""
506
+ set msg "static build of openssl in $dir"
507
+ set ssllibs "$dir/libssl.a $dir/libcrypto.a -lpthread"
508
+ if {[check-for-openssl $msg "$cflags $ldflags" $ssllibs]} {
509
+ incr found
510
+ break
511
+ }
512
+ }
513
+ }
514
+ }
462515
}
463516
if {$found} {
464
- define FOSSIL_ENABLE_SSL
465
- define-append EXTRA_CFLAGS $cflags
466
- define-append EXTRA_LDFLAGS $ldflags
467
- define-append CFLAGS $cflags
468
- define-append LDFLAGS $ldflags
469
- if {[info exists ssllibs]} {
470
- define-append LIBS $ssllibs
471
- } else {
472
- define-append LIBS -lssl -lcrypto
473
- }
474
- if {[info exists ::zlib_lib]} {
475
- define-append LIBS $::zlib_lib
476
- }
477
- if {[is_mingw]} {
478
- define-append LIBS -lgdi32 -lwsock32 -lcrypt32
479
- }
480
- msg-result "HTTPS support enabled"
481
-
482
- # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
483
- if {[string match *-darwin* [get-define host]]} {
484
- if {[cctest -cflags {-Wdeprecated-declarations}]} {
485
- define-append EXTRA_CFLAGS -Wdeprecated-declarations
486
- }
487
- }
488
- } else {
489
- user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
490
- }
491
-} else {
492
- if {[info exists ::zlib_lib]} {
493
- define-append LIBS $::zlib_lib
494
- }
495
-}
496
-
497
-
517
+ define FOSSIL_ENABLE_SSL
518
+ define-append EXTRA_CFLAGS $cflags
519
+ define-append EXTRA_LDFLAGS $ldflags
520
+ if {[info exists ssllibs]} {
521
+ define-append LIBS $ssllibs
522
+ } else {
523
+ define-append LIBS -lssl -lcrypto
524
+ }
525
+ if {[info exists ::zlib_lib]} {
526
+ define-append LIBS $::zlib_lib
527
+ }
528
+ if {[is_mingw]} {
529
+ define-append LIBS -lgdi32 -lwsock32 -lcrypt32
530
+ }
531
+ msg-result "HTTPS support enabled"
532
+
533
+ # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
534
+ if {[string match *-darwin* [get-define host]]} {
535
+ if {[cctest -cflags {-Wdeprecated-declarations}]} {
536
+ define-append EXTRA_CFLAGS -Wdeprecated-declarations
537
+ }
538
+ }
539
+ } else {
540
+ user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
541
+ }
542
+ } else {
543
+ if {[info exists ::zlib_lib]} {
544
+ define-append LIBS $::zlib_lib
545
+ }
546
+ }
547
+}; # handle-with-openssl
548
+
549
+#
550
+# CFLAGS_INCLUDE is ONLY for -I... flags and their order is
551
+# significant so that --with-sqlite=PATH's header can shadow our
552
+# own. <s>One caveat with this is that we cannot point
553
+# --with-sqlite=PATH to the root of sqlite3's own build tree because
554
+# that dir has a config.h which ends up shadowing src/config.h,
555
+# breaking our build.</s> (That is no longer true: that that config.h
556
+# was renamed to sqlite_cfg.h at some point.)
557
+#
558
+define CFLAGS_INCLUDE {}
498559
499560
########################################################################
500561
# --with-sqlite=PATH checks for the first it finds of the following...
501562
# - PATH/sqlite3.c and PATH/sqlite3.h
502563
# - PATH/sqlite3.o (and assumes sqlite3.h is with it)
503564
# - PATH/lib/libsqlite3* and PATH/include/sqlite3.h
504
-define CFLAGS_INCLUDE {}
505
-# ^^^ CFLAGS_INCLUDE is ONLY for -I... flags and their order is
506
-# significant so that --with-sqlite=PATH's header can shadow our
507
-# own. One caveat with this is that we cannot point --with-sqlite=PATH
508
-# to the root of sqlite3's own build tree because that dir has a
509
-# config.h which ends up shadowing src/config.h, breaking our build.
510
-set sq3path [opt-val with-sqlite]
511
-define SQLITE3_SRC.2 {}
512
-define SQLITE3_OBJ.2 {}
513
-define SQLITE3_SHELL_SRC.2 {$(SQLITE3_SHELL_SRC.0)}
514
-if {$sq3path in {tree ""}} {
515
- msg-result "Using sqlite3.c from this source tree."
516
-} else {
517
- # SQLITE3_ORIGIN:
518
- # 0 = local source tree
519
- # 1 = use external lib or sqlite3.o
520
- # 2 = use external sqlite3.c and (if found) shell.c
521
- define USE_SYSTEM_SQLITE 1
522
- define SQLITE3_ORIGIN 2
523
- if {$sq3path != "auto"} {
524
- if {([file exists $sq3path/sqlite3.c]) && \
525
- ([file exists $sq3path/sqlite3.h]) } {
526
- # Prefer sqlite3.[ch] if found.
527
- define SQLITE3_SRC.2 $sq3path/sqlite3.c
528
- define SQLITE3_OBJ.2 {$(SQLITE3_OBJ.0)}
529
- define USE_SYSTEM_SQLITE 2
530
- define SQLITE3_ORIGIN 2
531
- if {[file exists $sq3path/shell.c]} {
532
- define SQLITE3_SHELL_SRC.2 $sq3path/shell.c
533
- }
534
- define-append CFLAGS_INCLUDE -I$sq3path
535
- define-append EXTRA_LDFLAGS -lpthread
536
- # ^^^ additional -lXXX flags are conservative estimates
537
- msg-result "Using sqlite3.c and sqlite3.h from $sq3path"
538
- } elseif {[file exists $sq3path/sqlite3.o]} {
539
- # Use sqlite3.o if found.
540
- define SQLITE3_OBJ.2 $sq3path/sqlite3.o
541
- define-append CFLAGS_INCLUDE -I$sq3path
542
- define-append EXTRA_LDFLAGS $sq3path/sqlite3.o -lpthread
543
- # ^^^ additional -lXXX flags are conservative estimates
544
- msg-result "Using sqlite3.o from $sq3path"
545
- } elseif { ([llength [glob -nocomplain -directory $sq3path/lib libsqlite3*]] != 0) \
546
- && ([file exists $sq3path/include/sqlite3.h]) } {
547
- # e.g. --with-sqlite=/usr/local. Try $sq3path/lib/libsqlite3*
548
- # and $sq3path/include/sqlite3.h
549
- define-append CFLAGS_INCLUDE -I$sq3path/include
550
- define-append EXTRA_LDFLAGS -L$sq3path/lib -lsqlite3 -lpthread
551
- # ^^^ additional -lXXX flags are conservative estimates
552
- msg-result "Using -lsqlite3 from $sq3path"
553
- } else {
554
- # Assume $sq3path holds both the lib and header
555
- cc-with [list -cflags "-I$sq3path -L$sq3path"]
556
- define-append CFLAGS_INCLUDE -I$sq3path
557
- define-append EXTRA_LDFLAGS -L$sq3path -lsqlite3 -lpthread
558
- # ^^^ additional -lXXX flags are conservative estimates
559
- msg-result "Using -lsqlite3 from $sq3path"
560
- }
561
- } elseif {![cc-check-includes sqlite3.h] || ![check-function-in-lib sqlite3_open_v2 sqlite3]} {
562
- user-error "libsqlite3 not found please install it or specify the location with --with-sqlite"
563
- }
564
-}
565
-define-append CFLAGS_INCLUDE {-I. -I$(SRCDIR) -I$(SRCDIR_extsrc)}
566
-
567
-set tclpath [opt-val with-tcl]
568
-if {$tclpath ne ""} {
569
- set tclprivatestubs [opt-bool with-tcl-private-stubs]
570
- # Note parse-tclconfig-sh is in autosetup/local.tcl
571
- if {$tclpath eq "1"} {
572
- set tcldir [file dirname $autosetup(dir)]/compat/tcl-8.6
573
- if {$tclprivatestubs} {
574
- set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
575
- set tclconfig(TCL_VERSION) {Private Stubs}
576
- set tclconfig(TCL_PATCH_LEVEL) {}
577
- set tclconfig(TCL_PREFIX) $tcldir
578
- set tclconfig(TCL_LD_FLAGS) { }
579
- } else {
580
- # Use the system Tcl. Look in some likely places.
581
- array set tclconfig [parse-tclconfig-sh \
582
- $tcldir/unix $tcldir/win \
583
- /usr /usr/local /usr/share /opt/local]
584
- set msg "on your system"
585
- }
586
- } else {
587
- array set tclconfig [parse-tclconfig-sh $tclpath]
588
- set msg "at $tclpath"
589
- }
590
- if {[opt-bool static]} {
591
- set tclconfig(TCL_LD_FLAGS) { }
592
- }
593
- if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
594
- user-error "Cannot find Tcl $msg"
595
- }
596
- set tclstubs [opt-bool with-tcl-stubs]
597
- if {$tclprivatestubs} {
598
- define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
599
- define USE_TCL_STUBS
600
- } elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
601
- set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
602
- define FOSSIL_ENABLE_TCL_STUBS
603
- define USE_TCL_STUBS
604
- } else {
605
- set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
606
- }
607
- set cflags $tclconfig(TCL_INCLUDE_SPEC)
608
- if {!$tclprivatestubs} {
609
- set foundtcl 0; # Did we find a working Tcl library?
610
- cc-with [list -cflags $cflags -libs $libs] {
611
- if {$tclstubs} {
612
- if {[cc-check-functions Tcl_InitStubs]} {
613
- set foundtcl 1
614
- }
615
- } else {
616
- if {[cc-check-functions Tcl_CreateInterp]} {
617
- set foundtcl 1
618
- }
619
- }
620
- }
621
- if {!$foundtcl && [string match *-lieee* $libs]} {
622
- # On some systems, using "-lieee" from TCL_LIB_SPEC appears
623
- # to cause issues.
624
- msg-result "Removing \"-lieee\" and retrying for Tcl..."
625
- set libs [string map [list -lieee ""] $libs]
626
- cc-with [list -cflags $cflags -libs $libs] {
627
- if {$tclstubs} {
628
- if {[cc-check-functions Tcl_InitStubs]} {
629
- set foundtcl 1
630
- }
631
- } else {
632
- if {[cc-check-functions Tcl_CreateInterp]} {
633
- set foundtcl 1
634
- }
635
- }
636
- }
637
- }
638
- if {!$foundtcl && ![string match *-lpthread* $libs]} {
639
- # On some systems, TCL_LIB_SPEC appears to be missing
640
- # "-lpthread". Try adding it.
641
- msg-result "Adding \"-lpthread\" and retrying for Tcl..."
642
- set libs "$libs -lpthread"
643
- cc-with [list -cflags $cflags -libs $libs] {
644
- if {$tclstubs} {
645
- if {[cc-check-functions Tcl_InitStubs]} {
646
- set foundtcl 1
647
- }
648
- } else {
649
- if {[cc-check-functions Tcl_CreateInterp]} {
650
- set foundtcl 1
651
- }
652
- }
653
- }
654
- }
655
- if {!$foundtcl} {
656
- if {$tclstubs} {
657
- user-error "Cannot find a usable Tcl stubs library $msg"
658
- } else {
659
- user-error "Cannot find a usable Tcl library $msg"
660
- }
661
- }
662
- }
663
- set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
664
- msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
665
- if {!$tclprivatestubs} {
666
- define-append LIBS $libs
667
- }
668
- define-append EXTRA_CFLAGS $cflags
669
- define-append CFLAGS $cflags
670
- if {[info exists zlibpath] && $zlibpath eq "tree"} {
671
- #
672
- # NOTE: When using zlib in the source tree, prevent Tcl from
673
- # pulling in the system one.
674
- #
675
- set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
676
- $tclconfig(TCL_LD_FLAGS)]
677
- }
678
- #
679
- # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
680
- # be checked for near the bottom of this file.
681
- #
682
- set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
683
- $tclconfig(TCL_LD_FLAGS)]
684
- define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
685
- define FOSSIL_ENABLE_TCL
686
-}
687
-
688
-# Emscripten is a purely optional component used only for doing
689
-# in-tree builds of WASM stuff, as opposed to WASM binaries we import
690
-# from other places. This is only set up for Unix-style OSes and is
691
-# untested anywhere but Linux.
692
-set emsdkHome [opt-val with-emsdk]
693
-define EMSDK_HOME ""
694
-define EMSDK_ENV ""
695
-define EMCC_OPT "-Oz"
696
-if {$emsdkHome eq "" && [info exists ::env(EMSDK)]} {
697
- # Fall back to checking the environment. $EMSDK gets set
698
- # by sourcing emsdk_env.sh.
699
- set emsdkHome $::env(EMSDK)
700
-}
701
-if {$emsdkHome ne ""} {
702
- define EMSDK_HOME $emsdkHome
703
- set emsdkEnv "$emsdkHome/emsdk_env.sh"
704
- if {[file exists $emsdkEnv]} {
705
- puts "Using Emscripten SDK environment from $emsdkEnv."
706
- define EMSDK_ENV $emsdkEnv
707
- if {[info exists ::env(EMCC_OPT)]} {
708
- define EMCC_OPT $::env(EMCC_OPT)
709
- }
710
- } else {
711
- puts "emsdk_env.sh not found. Assuming emcc is in the PATH."
712
- }
713
-}
565
+proc handle-with-sqlite {} {
566
+ set sq3path [opt-val with-sqlite]
567
+ define SQLITE3_SRC.2 {}
568
+ define SQLITE3_OBJ.2 {}
569
+ define SQLITE3_SHELL_SRC.2 {$(SQLITE3_SHELL_SRC.0)}
570
+ if {$sq3path in {tree ""}} {
571
+ msg-result "Using sqlite3.c from this source tree."
572
+ } else {
573
+ # SQLITE3_ORIGIN:
574
+ # 0 = local source tree
575
+ # 1 = use external lib or sqlite3.o
576
+ # 2 = use external sqlite3.c and (if found) shell.c
577
+ define USE_SYSTEM_SQLITE 1
578
+ define SQLITE3_ORIGIN 2
579
+ if {$sq3path != "auto"} {
580
+ if {([file exists $sq3path/sqlite3.c]) &&
581
+ ([file exists $sq3path/sqlite3.h]) } {
582
+ # Prefer sqlite3.[ch] if found.
583
+ define SQLITE3_SRC.2 $sq3path/sqlite3.c
584
+ define SQLITE3_OBJ.2 {$(SQLITE3_OBJ.0)}
585
+ define USE_SYSTEM_SQLITE 2
586
+ define SQLITE3_ORIGIN 2
587
+ if {[file exists $sq3path/shell.c]} {
588
+ define SQLITE3_SHELL_SRC.2 $sq3path/shell.c
589
+ }
590
+ define-append CFLAGS_INCLUDE -I$sq3path
591
+ define-append EXTRA_LDFLAGS -lpthread
592
+ # ^^^ additional -lXXX flags are conservative estimates
593
+ msg-result "Using sqlite3.c and sqlite3.h from $sq3path"
594
+ } elseif {[file exists $sq3path/sqlite3.o]} {
595
+ # Use sqlite3.o if found.
596
+ define SQLITE3_OBJ.2 $sq3path/sqlite3.o
597
+ define-append CFLAGS_INCLUDE -I$sq3path
598
+ define-append EXTRA_LDFLAGS $sq3path/sqlite3.o -lpthread
599
+ # ^^^ additional -lXXX flags are conservative estimates
600
+ msg-result "Using sqlite3.o from $sq3path"
601
+ } elseif { ([llength [glob -nocomplain -directory $sq3path/lib libsqlite3*]] != 0) \
602
+ && ([file exists $sq3path/include/sqlite3.h]) } {
603
+ # e.g. --with-sqlite=/usr/local. Try $sq3path/lib/libsqlite3*
604
+ # and $sq3path/include/sqlite3.h
605
+ define-append CFLAGS_INCLUDE -I$sq3path/include
606
+ define-append EXTRA_LDFLAGS -L$sq3path/lib -lsqlite3 -lpthread
607
+ # ^^^ additional -lXXX flags are conservative estimates
608
+ msg-result "Using -lsqlite3 from $sq3path"
609
+ } else {
610
+ # Assume $sq3path holds both the lib and header
611
+ cc-with [list -cflags "-I$sq3path -L$sq3path"]
612
+ define-append CFLAGS_INCLUDE -I$sq3path
613
+ define-append EXTRA_LDFLAGS -L$sq3path -lsqlite3 -lpthread
614
+ # ^^^ additional -lXXX flags are conservative estimates
615
+ msg-result "Using -lsqlite3 from $sq3path"
616
+ }
617
+ } elseif {![cc-check-includes sqlite3.h] || ![check-function-in-lib sqlite3_open_v2 sqlite3]} {
618
+ user-error "libsqlite3 not found please install it or specify the location with --with-sqlite"
619
+ }
620
+ }
621
+}; # handle-with-sqlite
622
+handle-with-sqlite
623
+define-append CFLAGS_INCLUDE {-I. -I$(SRCDIR) -I$(SRCDIR_extsrc)}; # must be after handle-with-sqlite
624
+
625
+#
626
+# Handle the --with-tcl flag.
627
+#
628
+proc handle-with-tcl {} {
629
+ set tclpath [opt-val with-tcl]
630
+ if {$tclpath eq ""} {
631
+ return
632
+ }
633
+ set tclprivatestubs [opt-bool with-tcl-private-stubs]
634
+ # Note parse-tclconfig-sh is in autosetup/local.tcl
635
+ if {$tclpath eq "1"} {
636
+ set tcldir [file dirname $::autosetup(dir)]/compat/tcl-8.6
637
+ if {$tclprivatestubs} {
638
+ set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
639
+ set tclconfig(TCL_VERSION) {Private Stubs}
640
+ set tclconfig(TCL_PATCH_LEVEL) {}
641
+ set tclconfig(TCL_PREFIX) $tcldir
642
+ set tclconfig(TCL_LD_FLAGS) { }
643
+ } else {
644
+ # Use the system Tcl. Look in some likely places.
645
+ array set tclconfig [parse-tclconfig-sh \
646
+ $tcldir/unix $tcldir/win \
647
+ /usr /usr/local /usr/share /opt/local]
648
+ set msg "on your system"
649
+ }
650
+ } else {
651
+ array set tclconfig [parse-tclconfig-sh $tclpath]
652
+ set msg "at $tclpath"
653
+ }
654
+ if {[opt-bool static]} {
655
+ set tclconfig(TCL_LD_FLAGS) { }
656
+ }
657
+ if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
658
+ user-error "Cannot find Tcl $msg"
659
+ }
660
+ set tclstubs [opt-bool with-tcl-stubs]
661
+ if {$tclprivatestubs} {
662
+ define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
663
+ define USE_TCL_STUBS
664
+ } elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
665
+ set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
666
+ define FOSSIL_ENABLE_TCL_STUBS
667
+ define USE_TCL_STUBS
668
+ } else {
669
+ set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
670
+ }
671
+ set cflags $tclconfig(TCL_INCLUDE_SPEC)
672
+ if {!$tclprivatestubs} {
673
+ set foundtcl 0; # Did we find a working Tcl library?
674
+ cc-with [list -cflags $cflags -libs $libs] {
675
+ if {$tclstubs} {
676
+ if {[cc-check-functions Tcl_InitStubs]} {
677
+ set foundtcl 1
678
+ }
679
+ } else {
680
+ if {[cc-check-functions Tcl_CreateInterp]} {
681
+ set foundtcl 1
682
+ }
683
+ }
684
+ }
685
+ if {!$foundtcl && [string match *-lieee* $libs]} {
686
+ # On some systems, using "-lieee" from TCL_LIB_SPEC appears
687
+ # to cause issues.
688
+ msg-result "Removing \"-lieee\" and retrying for Tcl..."
689
+ set libs [string map [list -lieee ""] $libs]
690
+ cc-with [list -cflags $cflags -libs $libs] {
691
+ if {$tclstubs} {
692
+ if {[cc-check-functions Tcl_InitStubs]} {
693
+ set foundtcl 1
694
+ }
695
+ } else {
696
+ if {[cc-check-functions Tcl_CreateInterp]} {
697
+ set foundtcl 1
698
+ }
699
+ }
700
+ }
701
+ }
702
+ if {!$foundtcl && ![string match *-lpthread* $libs]} {
703
+ # On some systems, TCL_LIB_SPEC appears to be missing
704
+ # "-lpthread". Try adding it.
705
+ msg-result "Adding \"-lpthread\" and retrying for Tcl..."
706
+ set libs "$libs -lpthread"
707
+ cc-with [list -cflags $cflags -libs $libs] {
708
+ if {$tclstubs} {
709
+ if {[cc-check-functions Tcl_InitStubs]} {
710
+ set foundtcl 1
711
+ }
712
+ } else {
713
+ if {[cc-check-functions Tcl_CreateInterp]} {
714
+ set foundtcl 1
715
+ }
716
+ }
717
+ }
718
+ }
719
+ if {!$foundtcl} {
720
+ if {$tclstubs} {
721
+ user-error "Cannot find a usable Tcl stubs library $msg"
722
+ } else {
723
+ user-error "Cannot find a usable Tcl library $msg"
724
+ }
725
+ }
726
+ }
727
+ set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
728
+ msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
729
+ if {!$tclprivatestubs} {
730
+ define-append LIBS $libs
731
+ }
732
+ define-append EXTRA_CFLAGS $cflags
733
+ define-append CFLAGS $cflags
734
+ if {[info exists ::zlibpath] && $::zlibpath eq "tree"} {
735
+ #
736
+ # NOTE: When using zlib in the source tree, prevent Tcl from
737
+ # pulling in the system one.
738
+ #
739
+ set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
740
+ $tclconfig(TCL_LD_FLAGS)]
741
+ }
742
+ #
743
+ # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
744
+ # be checked for near the bottom of this file.
745
+ #
746
+ set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
747
+ $tclconfig(TCL_LD_FLAGS)]
748
+ define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
749
+ define FOSSIL_ENABLE_TCL
750
+}; # handle-with-tcl
751
+handle-with-tcl
714752
715753
# Network functions require libraries on some systems
716754
cc-check-function-in-lib gethostbyname nsl
717755
if {![cc-check-function-in-lib socket {socket network}]} {
718
- # Last resort, may be Windows
719
- if {[is_mingw]} {
720
- define-append LIBS -lwsock32
721
- }
756
+ # Last resort, may be Windows
757
+ if {[is_mingw]} {
758
+ define-append LIBS -lwsock32
759
+ }
722760
}
761
+
762
+# Some systems (ex: SunOS) require -lrt in order to use nanosleep
763
+cc-check-function-in-lib nanosleep rt
723764
724765
# The SMTP module requires special libraries and headers for MX DNS
725766
# record lookups and such.
726767
cc-check-includes arpa/nameser.h
727768
cc-include-needs bind/resolv.h netinet/in.h
@@ -732,11 +773,11 @@
732773
[cc-check-function-in-lib __ns_name_uncompress {bind resolv}]) &&
733774
([cc-check-function-in-lib ns_parserr {bind resolv}] ||
734775
[cc-check-function-in-lib __ns_parserr {bind resolv}]) &&
735776
([cc-check-function-in-lib res_query {bind resolv}] ||
736777
[cc-check-function-in-lib __res_query {bind resolv}]))} {
737
- msg-result "WARNING: SMTP feature will not be able to look up local MX."
778
+ msg-result "WARNING: SMTP feature will not be able to look up local MX."
738779
}
739780
cc-check-function-in-lib res_9_ns_initparse resolv
740781
741782
# Other nonstandard function checks
742783
cc-check-functions utime
@@ -744,15 +785,15 @@
744785
cc-check-functions strchrnul
745786
cc-check-functions pledge
746787
cc-check-functions backtrace
747788
748789
# Termux on Android adds "getpass(char *)" to unistd.h, so check this so we
749
-# guard against including it again; use cctest as cc-check-functions and
790
+# guard against including it again; use cctest as cc-check-functions and
750791
# cctest_function check for "getpass()" with no args and fail
751792
if {[cctest -link 1 -includes {unistd.h} -code "getpass(0);"]} {
752
- define FOSSIL_HAVE_GETPASS 1
753
- msg-result "Found getpass() with unistd.h"
793
+ define FOSSIL_HAVE_GETPASS 1
794
+ msg-result "Found getpass() with unistd.h"
754795
}
755796
756797
# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
757798
if {![cc-check-functions getloadavg] ||
758799
![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
@@ -760,44 +801,43 @@
760801
msg-result "Load average support unavailable"
761802
}
762803
763804
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
764805
if {![cc-check-functions getpassphrase]} {
765
- # Haiku needs this
766
- cc-check-function-in-lib getpass bsd
806
+ # Haiku needs this
807
+ cc-check-function-in-lib getpass bsd
767808
}
768
-cc-check-function-in-lib sin m
769809
770810
# Check for the FuseFS library
771811
if {[opt-bool fusefs]} {
772812
if {[opt-bool static]} {
773
- msg-result "FuseFS support disabled due to -static"
813
+ msg-result "FuseFS support disabled due to -static"
774814
} elseif {[cc-check-function-in-lib fuse_mount fuse]} {
775
- define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
776
- define FOSSIL_HAVE_FUSEFS 1
777
- msg-result "FuseFS support enabled"
815
+ define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
816
+ define FOSSIL_HAVE_FUSEFS 1
817
+ msg-result "FuseFS support enabled"
778818
}
779819
}
780820
781821
########################################################################
782822
# Checks the compiler for compile_commands.json support.
783823
#
784824
# Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes"
785825
# if supported, "no" if not.
786826
proc check-compile-commands {} {
787
- msg-checking "compile_commands.json support... "
788
- if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
789
- # This test reportedly incorrectly succeeds on one of
790
- # Martin G.'s older systems.
791
- msg-result "compiler supports compile_commands.json"
792
- define MAKE_COMPILATION_DB yes
793
- return 1
794
- } else {
795
- msg-result "compiler does not support compile_commands.json"
796
- define MAKE_COMPILATION_DB no
797
- return 0
798
- }
827
+ msg-checking "compile_commands.json support... "
828
+ if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
829
+ # This test reportedly incorrectly succeeds on one of
830
+ # Martin G.'s older systems.
831
+ msg-result "compiler supports compile_commands.json"
832
+ define MAKE_COMPILATION_DB yes
833
+ return 1
834
+ } else {
835
+ msg-result "compiler does not support compile_commands.json"
836
+ define MAKE_COMPILATION_DB no
837
+ return 0
838
+ }
799839
}
800840
801841
define MAKE_COMPILATION_DB no
802842
if {!$outOfTreeBuild} {
803843
if {[opt-bool compile-commands]} {
@@ -814,40 +854,114 @@
814854
# Add -fsanitize compile and link options late: we don't want the C
815855
# checks above to run with those sanitizers enabled. It can not only
816856
# be pointless, it can actually break correct tests.
817857
set fsan [opt-val with-sanitizer]
818858
if {[string length $fsan]} {
819
- define-append EXTRA_CFLAGS -fsanitize=$fsan
820
- define-append EXTRA_LDFLAGS -fsanitize=$fsan
821
- if {[string first "undefined" $fsan] != -1} {
822
- # We need to link with libubsan if we're compiling under
823
- # GCC with -fsanitize=undefined.
824
- cc-check-function-in-lib __ubsan_handle_add_overflow ubsan
825
- }
859
+ define-append EXTRA_CFLAGS -fsanitize=$fsan
860
+ define-append EXTRA_LDFLAGS -fsanitize=$fsan
861
+ if {[string first "undefined" $fsan] != -1} {
862
+ # We need to link with libubsan if we're compiling under
863
+ # GCC with -fsanitize=undefined.
864
+ cc-check-function-in-lib __ubsan_handle_add_overflow ubsan
865
+ }
826866
}
827867
828868
# Finally, append libraries that must be last. This matters more on some
829869
# OSes than others, but is most broadly required for static linking.
830870
if {[check-function-in-lib dlopen dl]} {
831
- # Some platforms (*BSD) have the dl functions already in libc and no libdl.
832
- # In such case we can link directly without -ldl.
833
- define-append LIBS [get-define lib_dlopen]
871
+ # Some platforms (*BSD) have the dl functions already in libc and no libdl.
872
+ # In such case we can link directly without -ldl.
873
+ define-append LIBS [get-define lib_dlopen]
834874
}
835875
if {[opt-bool static]} {
836
- # Linux can only infer the dependency on pthread from OpenSSL when
837
- # doing dynamic linkage.
838
- define-append LIBS -lpthread
876
+ # Linux can only infer the dependency on pthread from OpenSSL when
877
+ # doing dynamic linkage.
878
+ define-append LIBS -lpthread
879
+}
880
+
881
+
882
+########################################################################
883
+# @proj-check-emsdk
884
+#
885
+# Emscripten is used for doing in-tree builds of web-based WASM stuff,
886
+# as opposed to WASI-based WASM or WASM binaries we import from other
887
+# places. This is only set up for Unix-style OSes and is untested
888
+# anywhere but Linux. Requires that the --with-emsdk flag be
889
+# registered with autosetup.
890
+#
891
+# It looks for the SDK in the location specified by --with-emsdk.
892
+# Values of "" or "auto" mean to check for the environment var EMSDK
893
+# (which gets set by the emsdk_env.sh script from the SDK) or that
894
+# same var passed to configure.
895
+#
896
+# If the given directory is found, it expects to find emsdk_env.sh in
897
+# that directory, as well as the emcc compiler somewhere under there.
898
+#
899
+# If the --with-emsdk flag is explicitly provided and the SDK is not
900
+# found then a fatal error is generated, otherwise failure to find the
901
+# SDK is not fatal.
902
+#
903
+# Defines the following:
904
+#
905
+# - EMSDK_HOME = top dir of the emsdk or "".
906
+# - EMSDK_ENV_SH = path to EMSDK_HOME/emsdk_env.sh or ""
907
+# - BIN_EMCC = $EMSDK_HOME/upstream/emscripten/emcc or ""
908
+# - HAVE_EMSDK = 0 or 1 (this function's return value)
909
+#
910
+# Returns 1 if EMSDK_ENV_SH is found, else 0. If EMSDK_HOME is not empty
911
+# but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which
912
+# case we have to rely on the fact that sourcing $EMSDK_ENV_SH from a
913
+# shell will add emcc to the $PATH.
914
+proc proj-check-emsdk {} {
915
+ set emsdkHome [opt-val with-emsdk]
916
+ define EMSDK_HOME ""
917
+ define EMSDK_ENV_SH ""
918
+ define BIN_EMCC ""
919
+ set hadValue [llength $emsdkHome]
920
+ msg-checking "Emscripten SDK? "
921
+ if {$emsdkHome in {"" "auto"}} {
922
+ # Check the environment. $EMSDK gets set by sourcing emsdk_env.sh.
923
+ set emsdkHome [get-env EMSDK ""]
924
+ }
925
+ set rc 0
926
+ if {$emsdkHome ne ""} {
927
+ define EMSDK_HOME $emsdkHome
928
+ set emsdkEnv "$emsdkHome/emsdk_env.sh"
929
+ if {[file exists $emsdkEnv]} {
930
+ msg-result "$emsdkHome"
931
+ define EMSDK_ENV_SH $emsdkEnv
932
+ set rc 1
933
+ set emcc "$emsdkHome/upstream/emscripten/emcc"
934
+ if {[file exists $emcc]} {
935
+ define BIN_EMCC $emcc
936
+ }
937
+ } else {
938
+ msg-result "emsdk_env.sh not found in $emsdkHome"
939
+ }
940
+ } else {
941
+ msg-result "not found"
942
+ }
943
+ if {$hadValue && 0 == $rc} {
944
+ # Fail if it was explicitly requested but not found
945
+ proj-fatal "Cannot find the Emscripten SDK"
946
+ }
947
+ define HAVE_EMSDK $rc
948
+ return $rc
839949
}
840950
841
-if {[get-define EMSDK_HOME] ne ""} {
951
+if {[proj-check-emsdk]} {
842952
define EMCC_WRAPPER $::autosetup(dir)/../tools/emcc.sh
953
+ define EMCC_OPT [get-env EMCC_OPT "-Oz"]; # optional flags to pass to emcc
843954
make-template tools/emcc.sh.in
844955
catch {exec chmod u+x tools/emcc.sh}
845956
} else {
846957
define EMCC_WRAPPER ""
958
+ define EMCC_OPT ""
847959
catch {exec rm -f tools/emcc.sh}
848960
}
961
+
962
+handle-with-openssl
849963
850964
# Tag container builds with a prefix of the checkin ID of the version
851965
# of Fossil each one contains. This not only allows multiple images
852966
# to coexist and multiple containers to be created unamgiguosly from
853967
# them, it also changes the URL we fetch the source tarball from, so
854968
855969
ADDED extsrc/linenoise-win32.c
--- auto.def
+++ auto.def
@@ -41,12 +41,26 @@
41 define MINIMUM_SQLITE_VERSION "3.46.0"
42
43 # This is useful for people wanting Fossil to use an external SQLite library
44 # to compare the one they have against the minimum required
45 if {[opt-bool print-minimum-sqlite-version]} {
46 puts [get-define MINIMUM_SQLITE_VERSION]
47 exit 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48 }
49
50 set outOfTreeBuild 0
51 if {![file exists fossil.1]} {
52 puts "This appears to be an out-of-tree build."
@@ -53,21 +67,21 @@
53 set outOfTreeBuild 1
54 }
55
56 # sqlite wants these types if possible
57 cc-with {-includes {stdint.h inttypes.h}} {
58 cc-check-types uint32_t uint16_t int16_t uint8_t
59 }
60
61 # Use pread/pwrite system calls in place of seek + read/write if possible
62 define USE_PREAD [cc-check-functions pread]
63
64 # If we have cscope here, we'll use it in the "tags" target
65 if {[cc-check-progs cscope]} {
66 define COLLECT_CSCOPE_DATA "cscope -bR $::autosetup(srcdir)/src/*.\[ch\]"
67 } else {
68 define COLLECT_CSCOPE_DATA ""
69 }
70
71 # Find tclsh for the test suite.
72 #
73 # We can't use jimsh for this: the test suite uses features of Tcl that
@@ -80,35 +94,35 @@
80 # Ironically, this means we may right now be running under either jimsh0
81 # or a version of tclsh that we find unsuitable below!
82 cc-check-progs tclsh
83 set hbtd /usr/local/Cellar/tcl-tk
84 if {[string equal false [get-define TCLSH]]} {
85 msg-result "WARNING: 'make test' will not run here."
86 } else {
87 set v [exec /bin/sh -c "echo 'puts \$tcl_version' | tclsh"]
88 if {[expr {$v >= 8.6}]} {
89 msg-result "Found Tclsh version $v in the PATH."
90 define TCLSH tclsh
91 } elseif {[file isdirectory $hbtd]} {
92 # This is a macOS system with the Homebrew version of Tcl/Tk
93 # installed. Select the newest version. It won't normally be
94 # in the PATH to avoid shadowing /usr/bin/tclsh, and even if it
95 # were in the PATH, it's bad practice to put /usr/local/bin (the
96 # Homebrew default) ahead of /usr/bin, especially given that
97 # it's user-writeable by default with Homebrew. Thus, we can be
98 # pretty sure the only way to call it is with an absolute path.
99 set v [exec ls -tr $hbtd | tail -1]
100 set path "$hbtd/$v/bin/tclsh"
101 define TCLSH $path
102 msg-result "Using Homebrew Tcl/Tk version $path."
103 } else {
104 msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
105 define TCLSH false ;# force "make test" failure via /usr/bin/false
106 }
107 }
108
109 define CFLAGS [get-env CFLAGS "-g -O2"]
110 define EXTRA_CFLAGS "-Wall"
111 define EXTRA_LDFLAGS ""
112 define USE_SYSTEM_SQLITE 0
113 define USE_LINENOISE 0
114 define USE_MMAN_H 0
@@ -119,48 +133,48 @@
119 # SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
120
121 # Maintain the C89/C90-style order of variable declarations before statements.
122 # Check if the compiler supports the respective warning flag.
123 if {[cctest -cflags -Wdeclaration-after-statement]} {
124 define-append EXTRA_CFLAGS -Wdeclaration-after-statement
125 }
126
127
128 # This procedure is a customized version of "cc-check-function-in-lib",
129 # that does not modify the LIBS variable. Its use prevents prematurely
130 # pulling in libraries that will be added later anyhow (e.g. "-ldl").
131 proc check-function-in-lib {function libs {otherlibs {}}} {
132 if {[string length $otherlibs]} {
133 msg-checking "Checking for $function in $libs with $otherlibs..."
134 } else {
135 msg-checking "Checking for $function in $libs..."
136 }
137 set found 0
138 cc-with [list -libs $otherlibs] {
139 if {[cctest_function $function]} {
140 msg-result "none needed"
141 define lib_$function ""
142 incr found
143 } else {
144 foreach lib $libs {
145 cc-with [list -libs -l$lib] {
146 if {[cctest_function $function]} {
147 msg-result -l$lib
148 define lib_$function -l$lib
149 incr found
150 break
151 }
152 }
153 }
154 }
155 }
156 if {$found} {
157 define [feature-define-name $function]
158 } else {
159 msg-result "no"
160 }
161 return $found
162 }
163
164 if {![opt-bool internal-sqlite]} {
165 proc find_system_sqlite {} {
166
@@ -205,17 +219,17 @@
205 set sqlite-version [string cat "-D MINIMUM_SQLITE_VERSION=" [get-define MINIMUM_SQLITE_VERSION]]
206 lappend cmdline {*}[set sqlite-version]
207 set ok 1
208 set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
209 if {$err} {
210 configlog "Failed: [join $cmdline]"
211 if {[string length $result]>0} {configlog $result}
212 configlog "============"
213 set ok 0
214 } elseif {$::autosetup(debug)} {
215 configlog "Compiled OK: [join $cmdline]"
216 configlog "============"
217 }
218 if {!$ok} {
219 user-error "unable to compile SQLite compatibility test program"
220 }
221 set err [catch {exec-with-stderr ./conftest__} result errinfo]
@@ -230,498 +244,525 @@
230 test_system_sqlite
231
232 }
233
234 proc is_mingw {} {
235 return [string match *mingw* [get-define host]]
236 }
237
238 if {[is_mingw]} {
239 define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
240 define-append LIBS -lkernel32 -lws2_32
241 } else {
242 #
243 # NOTE: All platforms except MinGW should use the linenoise
244 # package. It is currently unsupported on Win32.
245 #
246 define USE_LINENOISE 1
247 }
248
249 if {[string match *-solaris* [get-define host]]} {
250 define-append EXTRA_CFLAGS {-D__EXTENSIONS__}
251 }
252
253 if {[opt-bool fossil-debug]} {
254 define CFLAGS {-g -O0 -Wall}
255 define-append CFLAGS -DFOSSIL_DEBUG
256 msg-result "Debugging support enabled"
257 }
258
259 if {[opt-bool no-opt]} {
260 define CFLAGS {-g -O0 -Wall}
261 msg-result "Builting without compiler optimization"
262 if {[opt-bool fossil-debug]} {
263 define-append CFLAGS -DFOSSIL_DEBUG
264 }
265 }
266
267 if {[opt-bool with-mman]} {
268 define-append EXTRA_CFLAGS -DUSE_MMAN_H
269 define USE_MMAN_H 1
270 msg-result "Enabling \"sys/mman.h\" support"
 
 
 
271 }
272
273 if {[opt-bool with-see]} {
274 define-append EXTRA_CFLAGS -DUSE_SEE
275 define USE_SEE 1
276 define SQLITE3_ORIGIN 1
277 msg-result "Enabling encryption support"
278 }
279
280 if {[opt-bool json]} {
281 # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
282 # is required in the CFLAGS because json*.c
283 # have #ifdef guards around the whole file without
284 # reading config.h first.
285 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
286 define FOSSIL_ENABLE_JSON
287 msg-result "JSON support enabled"
288 }
289
290 if {[opt-bool with-exec-rel-paths]} {
291 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS
292 define FOSSIL_ENABLE_EXEC_REL_PATHS
293 msg-result "Relative paths in external diff/gdiff enabled"
294 }
295
296 if {[opt-bool with-th1-docs]} {
297 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS
298 define FOSSIL_ENABLE_TH1_DOCS
299 msg-result "TH1 embedded documentation support enabled"
300 }
301
302 if {[opt-bool with-th1-hooks]} {
303 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS
304 define FOSSIL_ENABLE_TH1_HOOKS
305 msg-result "TH1 hooks support enabled"
306 }
307
308 #if {[opt-bool markdown]} {
309 # # no-op. Markdown is now enabled by default.
310 # msg-result "Markdown support enabled"
311 #}
312
313 if {[opt-bool static]} {
314 # XXX: This will not work on all systems.
315 define-append EXTRA_LDFLAGS -static
316 msg-result "Trying to link statically"
317 } else {
318 define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
319 define FOSSIL_DYNAMIC_BUILD
320 }
321
322 # Check for libraries that need to be sorted out early
323 cc-check-function-in-lib iconv iconv
324
 
 
 
325 # Helper for OpenSSL checking
326 proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto -lpthread}}} {
327 msg-checking "Checking for $msg..."
328 set rc 0
329 if {[is_mingw]} {
330 lappend libs -lgdi32 -lwsock32 -lcrypt32
331 }
332 if {[info exists ::zlib_lib]} {
333 lappend libs $::zlib_lib
334 }
335 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
336 if {[cc-check-includes openssl/ssl.h] && \
337 [cc-check-functions SSL_new]} {
338 incr rc
339 }
340 }
341 if {!$rc && ![is_mingw]} {
342 # On some systems, OpenSSL appears to require -ldl to link.
343 lappend libs -ldl
344 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
345 if {[cc-check-includes openssl/ssl.h] && \
346 [cc-check-functions SSL_new]} {
347 incr rc
348 }
349 }
350 }
351 if {$rc} {
352 msg-result "ok"
353 return 1
354 } else {
355 msg-result "no"
356 return 0
357 }
358 }
359
 
360 # Check for zlib, using the given location if specified
361 set zlibpath [opt-val with-zlib]
362 if {$zlibpath eq "tree"} {
363 set zlibdir [file dirname $autosetup(dir)]/compat/zlib
364 if {![file isdirectory $zlibdir]} {
365 user-error "The zlib in source tree directory does not exist"
366 } elseif { ([llength [glob -nocomplain -directory $zlibdir libz*]] == 0) } {
367 user-error "With --with-zlib=tree, $zlibdir must be configured and built first."
368 }
369 cc-with [list -cflags "-I$zlibdir -L$zlibdir"]
370 define-append EXTRA_CFLAGS -I$zlibdir
371 define-append LIBS $zlibdir/libz.a
372 set ::zlib_lib $zlibdir/libz.a
373 msg-result "Using zlib in source tree"
374 } else {
375 set cftry {""}
376 set ldtry {""}
377 if {$zlibpath ni {auto ""}} {
378 lappend cftry "-I$zlibpath"
379 lappend cftry "-I$zlibpath/include"
380 lappend ldtry "-L$zlibpath"
381 lappend ldtry "-L$zlibpath/lib"
382 }
383
384 # Reverse the list of tests so we check most-specific to least, else
385 # platform devel files will shadow local --with-zlib overrides.
386 foreach c [lreverse $cftry] {
387 if {[cc-with [list -cflags $c] {cc-check-includes zlib.h}]} {
388 if {$c eq ""} {
389 msg-result "Found zlib.h in default include path"
390 } else {
391 define-append EXTRA_CFLAGS "$c"
392 msg-result "Found zlib.h via $c"
393 }
394 set cfound $c
395 break
396 }
397 }
398 if {![info exists cfound]} {
399 user-error "zlib.h not found; either install it or specify its location via --with-zlib"
400 }
401 foreach lcheck [lreverse $ldtry] {
402 if {[cc-with [list -cflags "$cfound $lcheck"] {check-function-in-lib inflateEnd z}]} {
403 if {$lcheck eq ""} {
404 msg-result "Linked to zlib via default library path"
405 } else {
406 define-append EXTRA_LDFLAGS "$lcheck"
407 msg-result "Linked to zlib via $lcheck"
408 }
409 if {![check-function-in-lib compressBound z]} {
410 puts "Notice: disabling zlib compression in the SQL shell"
411 define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
412 }
413 break
414 }
415 }
416 set ::zlib_lib -lz
417 }
418
419 set ssldirs [opt-val with-openssl]
420 if {$ssldirs ne "none"} {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421 set found 0
422 if {$ssldirs eq "tree"} {
423 set ssldir [file dirname $autosetup(dir)]/compat/openssl
424 if {![file isdirectory $ssldir]} {
425 user-error "The OpenSSL in source tree directory does not exist"
426 }
427 set msg "ssl in $ssldir"
428 set cflags "-I$ssldir/include"
429 set ldflags "-L$ssldir"
430 set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
431 set found [check-for-openssl "ssl in source tree" "$cflags $ldflags" $ssllibs]
432 } else {
433 if {$ssldirs in {auto ""}} {
434 catch {
435 set cflags [exec pkg-config openssl --cflags-only-I]
436 set ldflags [exec pkg-config openssl --libs-only-L]
437 set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
438 } msg
439 if {!$found} {
440 set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \
 
441 /usr/pkg /usr/local /usr /usr/local/opt/openssl \
442 /opt/homebrew/opt/openssl"
443 }
444 }
445 if {!$found} {
446 foreach dir $ssldirs {
447 if {$dir eq ""} {
448 set msg "system ssl"
449 set cflags ""
450 set ldflags ""
451 } else {
452 set msg "ssl in $dir"
453 set cflags "-I$dir/include"
454 set ldflags "-L$dir/lib"
455 }
456 if {[check-for-openssl $msg "$cflags $ldflags"]} {
457 incr found
458 break
459 }
460 }
461 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462 }
463 if {$found} {
464 define FOSSIL_ENABLE_SSL
465 define-append EXTRA_CFLAGS $cflags
466 define-append EXTRA_LDFLAGS $ldflags
467 define-append CFLAGS $cflags
468 define-append LDFLAGS $ldflags
469 if {[info exists ssllibs]} {
470 define-append LIBS $ssllibs
471 } else {
472 define-append LIBS -lssl -lcrypto
473 }
474 if {[info exists ::zlib_lib]} {
475 define-append LIBS $::zlib_lib
476 }
477 if {[is_mingw]} {
478 define-append LIBS -lgdi32 -lwsock32 -lcrypt32
479 }
480 msg-result "HTTPS support enabled"
481
482 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
483 if {[string match *-darwin* [get-define host]]} {
484 if {[cctest -cflags {-Wdeprecated-declarations}]} {
485 define-append EXTRA_CFLAGS -Wdeprecated-declarations
486 }
487 }
488 } else {
489 user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
490 }
491 } else {
492 if {[info exists ::zlib_lib]} {
493 define-append LIBS $::zlib_lib
494 }
495 }
496
497
 
 
 
 
 
 
 
 
498
499 ########################################################################
500 # --with-sqlite=PATH checks for the first it finds of the following...
501 # - PATH/sqlite3.c and PATH/sqlite3.h
502 # - PATH/sqlite3.o (and assumes sqlite3.h is with it)
503 # - PATH/lib/libsqlite3* and PATH/include/sqlite3.h
504 define CFLAGS_INCLUDE {}
505 # ^^^ CFLAGS_INCLUDE is ONLY for -I... flags and their order is
506 # significant so that --with-sqlite=PATH's header can shadow our
507 # own. One caveat with this is that we cannot point --with-sqlite=PATH
508 # to the root of sqlite3's own build tree because that dir has a
509 # config.h which ends up shadowing src/config.h, breaking our build.
510 set sq3path [opt-val with-sqlite]
511 define SQLITE3_SRC.2 {}
512 define SQLITE3_OBJ.2 {}
513 define SQLITE3_SHELL_SRC.2 {$(SQLITE3_SHELL_SRC.0)}
514 if {$sq3path in {tree ""}} {
515 msg-result "Using sqlite3.c from this source tree."
516 } else {
517 # SQLITE3_ORIGIN:
518 # 0 = local source tree
519 # 1 = use external lib or sqlite3.o
520 # 2 = use external sqlite3.c and (if found) shell.c
521 define USE_SYSTEM_SQLITE 1
522 define SQLITE3_ORIGIN 2
523 if {$sq3path != "auto"} {
524 if {([file exists $sq3path/sqlite3.c]) && \
525 ([file exists $sq3path/sqlite3.h]) } {
526 # Prefer sqlite3.[ch] if found.
527 define SQLITE3_SRC.2 $sq3path/sqlite3.c
528 define SQLITE3_OBJ.2 {$(SQLITE3_OBJ.0)}
529 define USE_SYSTEM_SQLITE 2
530 define SQLITE3_ORIGIN 2
531 if {[file exists $sq3path/shell.c]} {
532 define SQLITE3_SHELL_SRC.2 $sq3path/shell.c
533 }
534 define-append CFLAGS_INCLUDE -I$sq3path
535 define-append EXTRA_LDFLAGS -lpthread
536 # ^^^ additional -lXXX flags are conservative estimates
537 msg-result "Using sqlite3.c and sqlite3.h from $sq3path"
538 } elseif {[file exists $sq3path/sqlite3.o]} {
539 # Use sqlite3.o if found.
540 define SQLITE3_OBJ.2 $sq3path/sqlite3.o
541 define-append CFLAGS_INCLUDE -I$sq3path
542 define-append EXTRA_LDFLAGS $sq3path/sqlite3.o -lpthread
543 # ^^^ additional -lXXX flags are conservative estimates
544 msg-result "Using sqlite3.o from $sq3path"
545 } elseif { ([llength [glob -nocomplain -directory $sq3path/lib libsqlite3*]] != 0) \
546 && ([file exists $sq3path/include/sqlite3.h]) } {
547 # e.g. --with-sqlite=/usr/local. Try $sq3path/lib/libsqlite3*
548 # and $sq3path/include/sqlite3.h
549 define-append CFLAGS_INCLUDE -I$sq3path/include
550 define-append EXTRA_LDFLAGS -L$sq3path/lib -lsqlite3 -lpthread
551 # ^^^ additional -lXXX flags are conservative estimates
552 msg-result "Using -lsqlite3 from $sq3path"
553 } else {
554 # Assume $sq3path holds both the lib and header
555 cc-with [list -cflags "-I$sq3path -L$sq3path"]
556 define-append CFLAGS_INCLUDE -I$sq3path
557 define-append EXTRA_LDFLAGS -L$sq3path -lsqlite3 -lpthread
558 # ^^^ additional -lXXX flags are conservative estimates
559 msg-result "Using -lsqlite3 from $sq3path"
560 }
561 } elseif {![cc-check-includes sqlite3.h] || ![check-function-in-lib sqlite3_open_v2 sqlite3]} {
562 user-error "libsqlite3 not found please install it or specify the location with --with-sqlite"
563 }
564 }
565 define-append CFLAGS_INCLUDE {-I. -I$(SRCDIR) -I$(SRCDIR_extsrc)}
566
567 set tclpath [opt-val with-tcl]
568 if {$tclpath ne ""} {
569 set tclprivatestubs [opt-bool with-tcl-private-stubs]
570 # Note parse-tclconfig-sh is in autosetup/local.tcl
571 if {$tclpath eq "1"} {
572 set tcldir [file dirname $autosetup(dir)]/compat/tcl-8.6
573 if {$tclprivatestubs} {
574 set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
575 set tclconfig(TCL_VERSION) {Private Stubs}
576 set tclconfig(TCL_PATCH_LEVEL) {}
577 set tclconfig(TCL_PREFIX) $tcldir
578 set tclconfig(TCL_LD_FLAGS) { }
579 } else {
580 # Use the system Tcl. Look in some likely places.
581 array set tclconfig [parse-tclconfig-sh \
582 $tcldir/unix $tcldir/win \
583 /usr /usr/local /usr/share /opt/local]
584 set msg "on your system"
585 }
586 } else {
587 array set tclconfig [parse-tclconfig-sh $tclpath]
588 set msg "at $tclpath"
589 }
590 if {[opt-bool static]} {
591 set tclconfig(TCL_LD_FLAGS) { }
592 }
593 if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
594 user-error "Cannot find Tcl $msg"
595 }
596 set tclstubs [opt-bool with-tcl-stubs]
597 if {$tclprivatestubs} {
598 define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
599 define USE_TCL_STUBS
600 } elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
601 set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
602 define FOSSIL_ENABLE_TCL_STUBS
603 define USE_TCL_STUBS
604 } else {
605 set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
606 }
607 set cflags $tclconfig(TCL_INCLUDE_SPEC)
608 if {!$tclprivatestubs} {
609 set foundtcl 0; # Did we find a working Tcl library?
610 cc-with [list -cflags $cflags -libs $libs] {
611 if {$tclstubs} {
612 if {[cc-check-functions Tcl_InitStubs]} {
613 set foundtcl 1
614 }
615 } else {
616 if {[cc-check-functions Tcl_CreateInterp]} {
617 set foundtcl 1
618 }
619 }
620 }
621 if {!$foundtcl && [string match *-lieee* $libs]} {
622 # On some systems, using "-lieee" from TCL_LIB_SPEC appears
623 # to cause issues.
624 msg-result "Removing \"-lieee\" and retrying for Tcl..."
625 set libs [string map [list -lieee ""] $libs]
626 cc-with [list -cflags $cflags -libs $libs] {
627 if {$tclstubs} {
628 if {[cc-check-functions Tcl_InitStubs]} {
629 set foundtcl 1
630 }
631 } else {
632 if {[cc-check-functions Tcl_CreateInterp]} {
633 set foundtcl 1
634 }
635 }
636 }
637 }
638 if {!$foundtcl && ![string match *-lpthread* $libs]} {
639 # On some systems, TCL_LIB_SPEC appears to be missing
640 # "-lpthread". Try adding it.
641 msg-result "Adding \"-lpthread\" and retrying for Tcl..."
642 set libs "$libs -lpthread"
643 cc-with [list -cflags $cflags -libs $libs] {
644 if {$tclstubs} {
645 if {[cc-check-functions Tcl_InitStubs]} {
646 set foundtcl 1
647 }
648 } else {
649 if {[cc-check-functions Tcl_CreateInterp]} {
650 set foundtcl 1
651 }
652 }
653 }
654 }
655 if {!$foundtcl} {
656 if {$tclstubs} {
657 user-error "Cannot find a usable Tcl stubs library $msg"
658 } else {
659 user-error "Cannot find a usable Tcl library $msg"
660 }
661 }
662 }
663 set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
664 msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
665 if {!$tclprivatestubs} {
666 define-append LIBS $libs
667 }
668 define-append EXTRA_CFLAGS $cflags
669 define-append CFLAGS $cflags
670 if {[info exists zlibpath] && $zlibpath eq "tree"} {
671 #
672 # NOTE: When using zlib in the source tree, prevent Tcl from
673 # pulling in the system one.
674 #
675 set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
676 $tclconfig(TCL_LD_FLAGS)]
677 }
678 #
679 # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
680 # be checked for near the bottom of this file.
681 #
682 set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
683 $tclconfig(TCL_LD_FLAGS)]
684 define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
685 define FOSSIL_ENABLE_TCL
686 }
687
688 # Emscripten is a purely optional component used only for doing
689 # in-tree builds of WASM stuff, as opposed to WASM binaries we import
690 # from other places. This is only set up for Unix-style OSes and is
691 # untested anywhere but Linux.
692 set emsdkHome [opt-val with-emsdk]
693 define EMSDK_HOME ""
694 define EMSDK_ENV ""
695 define EMCC_OPT "-Oz"
696 if {$emsdkHome eq "" && [info exists ::env(EMSDK)]} {
697 # Fall back to checking the environment. $EMSDK gets set
698 # by sourcing emsdk_env.sh.
699 set emsdkHome $::env(EMSDK)
700 }
701 if {$emsdkHome ne ""} {
702 define EMSDK_HOME $emsdkHome
703 set emsdkEnv "$emsdkHome/emsdk_env.sh"
704 if {[file exists $emsdkEnv]} {
705 puts "Using Emscripten SDK environment from $emsdkEnv."
706 define EMSDK_ENV $emsdkEnv
707 if {[info exists ::env(EMCC_OPT)]} {
708 define EMCC_OPT $::env(EMCC_OPT)
709 }
710 } else {
711 puts "emsdk_env.sh not found. Assuming emcc is in the PATH."
712 }
713 }
714
715 # Network functions require libraries on some systems
716 cc-check-function-in-lib gethostbyname nsl
717 if {![cc-check-function-in-lib socket {socket network}]} {
718 # Last resort, may be Windows
719 if {[is_mingw]} {
720 define-append LIBS -lwsock32
721 }
722 }
 
 
 
723
724 # The SMTP module requires special libraries and headers for MX DNS
725 # record lookups and such.
726 cc-check-includes arpa/nameser.h
727 cc-include-needs bind/resolv.h netinet/in.h
@@ -732,11 +773,11 @@
732 [cc-check-function-in-lib __ns_name_uncompress {bind resolv}]) &&
733 ([cc-check-function-in-lib ns_parserr {bind resolv}] ||
734 [cc-check-function-in-lib __ns_parserr {bind resolv}]) &&
735 ([cc-check-function-in-lib res_query {bind resolv}] ||
736 [cc-check-function-in-lib __res_query {bind resolv}]))} {
737 msg-result "WARNING: SMTP feature will not be able to look up local MX."
738 }
739 cc-check-function-in-lib res_9_ns_initparse resolv
740
741 # Other nonstandard function checks
742 cc-check-functions utime
@@ -744,15 +785,15 @@
744 cc-check-functions strchrnul
745 cc-check-functions pledge
746 cc-check-functions backtrace
747
748 # Termux on Android adds "getpass(char *)" to unistd.h, so check this so we
749 # guard against including it again; use cctest as cc-check-functions and
750 # cctest_function check for "getpass()" with no args and fail
751 if {[cctest -link 1 -includes {unistd.h} -code "getpass(0);"]} {
752 define FOSSIL_HAVE_GETPASS 1
753 msg-result "Found getpass() with unistd.h"
754 }
755
756 # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
757 if {![cc-check-functions getloadavg] ||
758 ![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
@@ -760,44 +801,43 @@
760 msg-result "Load average support unavailable"
761 }
762
763 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
764 if {![cc-check-functions getpassphrase]} {
765 # Haiku needs this
766 cc-check-function-in-lib getpass bsd
767 }
768 cc-check-function-in-lib sin m
769
770 # Check for the FuseFS library
771 if {[opt-bool fusefs]} {
772 if {[opt-bool static]} {
773 msg-result "FuseFS support disabled due to -static"
774 } elseif {[cc-check-function-in-lib fuse_mount fuse]} {
775 define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
776 define FOSSIL_HAVE_FUSEFS 1
777 msg-result "FuseFS support enabled"
778 }
779 }
780
781 ########################################################################
782 # Checks the compiler for compile_commands.json support.
783 #
784 # Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes"
785 # if supported, "no" if not.
786 proc check-compile-commands {} {
787 msg-checking "compile_commands.json support... "
788 if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
789 # This test reportedly incorrectly succeeds on one of
790 # Martin G.'s older systems.
791 msg-result "compiler supports compile_commands.json"
792 define MAKE_COMPILATION_DB yes
793 return 1
794 } else {
795 msg-result "compiler does not support compile_commands.json"
796 define MAKE_COMPILATION_DB no
797 return 0
798 }
799 }
800
801 define MAKE_COMPILATION_DB no
802 if {!$outOfTreeBuild} {
803 if {[opt-bool compile-commands]} {
@@ -814,40 +854,114 @@
814 # Add -fsanitize compile and link options late: we don't want the C
815 # checks above to run with those sanitizers enabled. It can not only
816 # be pointless, it can actually break correct tests.
817 set fsan [opt-val with-sanitizer]
818 if {[string length $fsan]} {
819 define-append EXTRA_CFLAGS -fsanitize=$fsan
820 define-append EXTRA_LDFLAGS -fsanitize=$fsan
821 if {[string first "undefined" $fsan] != -1} {
822 # We need to link with libubsan if we're compiling under
823 # GCC with -fsanitize=undefined.
824 cc-check-function-in-lib __ubsan_handle_add_overflow ubsan
825 }
826 }
827
828 # Finally, append libraries that must be last. This matters more on some
829 # OSes than others, but is most broadly required for static linking.
830 if {[check-function-in-lib dlopen dl]} {
831 # Some platforms (*BSD) have the dl functions already in libc and no libdl.
832 # In such case we can link directly without -ldl.
833 define-append LIBS [get-define lib_dlopen]
834 }
835 if {[opt-bool static]} {
836 # Linux can only infer the dependency on pthread from OpenSSL when
837 # doing dynamic linkage.
838 define-append LIBS -lpthread
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
839 }
840
841 if {[get-define EMSDK_HOME] ne ""} {
842 define EMCC_WRAPPER $::autosetup(dir)/../tools/emcc.sh
 
843 make-template tools/emcc.sh.in
844 catch {exec chmod u+x tools/emcc.sh}
845 } else {
846 define EMCC_WRAPPER ""
 
847 catch {exec rm -f tools/emcc.sh}
848 }
 
 
849
850 # Tag container builds with a prefix of the checkin ID of the version
851 # of Fossil each one contains. This not only allows multiple images
852 # to coexist and multiple containers to be created unamgiguosly from
853 # them, it also changes the URL we fetch the source tarball from, so
854
855 DDED extsrc/linenoise-win32.c
--- auto.def
+++ auto.def
@@ -41,12 +41,26 @@
41 define MINIMUM_SQLITE_VERSION "3.46.0"
42
43 # This is useful for people wanting Fossil to use an external SQLite library
44 # to compare the one they have against the minimum required
45 if {[opt-bool print-minimum-sqlite-version]} {
46 puts [get-define MINIMUM_SQLITE_VERSION]
47 exit 0
48 }
49
50 # Space characters have never been allowed in either the source
51 # tree nor the build directory. But the resulting error messages
52 # could be confusing. The following checks make the reason for the
53 # failure clear.
54 #
55 if {[string first " " $autosetup(srcdir)] != -1} {
56 user-error "The pathname of the source tree\
57 may not contain space characters"
58 }
59 if {[string first " " $autosetup(builddir)] != -1} {
60 user-error "The pathname of the build directory\
61 may not contain space characters"
62 }
63
64 set outOfTreeBuild 0
65 if {![file exists fossil.1]} {
66 puts "This appears to be an out-of-tree build."
@@ -53,21 +67,21 @@
67 set outOfTreeBuild 1
68 }
69
70 # sqlite wants these types if possible
71 cc-with {-includes {stdint.h inttypes.h}} {
72 cc-check-types uint32_t uint16_t int16_t uint8_t
73 }
74
75 # Use pread/pwrite system calls in place of seek + read/write if possible
76 define USE_PREAD [cc-check-functions pread]
77
78 # If we have cscope here, we'll use it in the "tags" target
79 if {[cc-check-progs cscope]} {
80 define COLLECT_CSCOPE_DATA "cscope -bR $::autosetup(srcdir)/src/*.\[ch\]"
81 } else {
82 define COLLECT_CSCOPE_DATA ""
83 }
84
85 # Find tclsh for the test suite.
86 #
87 # We can't use jimsh for this: the test suite uses features of Tcl that
@@ -80,35 +94,35 @@
94 # Ironically, this means we may right now be running under either jimsh0
95 # or a version of tclsh that we find unsuitable below!
96 cc-check-progs tclsh
97 set hbtd /usr/local/Cellar/tcl-tk
98 if {[string equal false [get-define TCLSH]]} {
99 msg-result "WARNING: 'make test' will not run here."
100 } else {
101 set v [exec sh -c "echo 'puts \$tcl_version' | tclsh"]
102 if {[expr {$v >= 8.6}]} {
103 msg-result "Found Tclsh version $v in the PATH."
104 define TCLSH tclsh
105 } elseif {[file isdirectory $hbtd]} {
106 # This is a macOS system with the Homebrew version of Tcl/Tk
107 # installed. Select the newest version. It won't normally be
108 # in the PATH to avoid shadowing /usr/bin/tclsh, and even if it
109 # were in the PATH, it's bad practice to put /usr/local/bin (the
110 # Homebrew default) ahead of /usr/bin, especially given that
111 # it's user-writeable by default with Homebrew. Thus, we can be
112 # pretty sure the only way to call it is with an absolute path.
113 set v [exec ls -tr $hbtd | tail -1]
114 set path "$hbtd/$v/bin/tclsh"
115 define TCLSH $path
116 msg-result "Using Homebrew Tcl/Tk version $path."
117 } else {
118 msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
119 define TCLSH false ;# force "make test" failure via /usr/bin/false
120 }
121 }
122
123 define CFLAGS [get-env CFLAGS "-g -Os"]
124 define EXTRA_CFLAGS "-Wall"
125 define EXTRA_LDFLAGS ""
126 define USE_SYSTEM_SQLITE 0
127 define USE_LINENOISE 0
128 define USE_MMAN_H 0
@@ -119,48 +133,48 @@
133 # SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
134
135 # Maintain the C89/C90-style order of variable declarations before statements.
136 # Check if the compiler supports the respective warning flag.
137 if {[cctest -cflags -Wdeclaration-after-statement]} {
138 define-append EXTRA_CFLAGS -Wdeclaration-after-statement
139 }
140
141
142 # This procedure is a customized version of "cc-check-function-in-lib",
143 # that does not modify the LIBS variable. Its use prevents prematurely
144 # pulling in libraries that will be added later anyhow (e.g. "-ldl").
145 proc check-function-in-lib {function libs {otherlibs {}}} {
146 if {[string length $otherlibs]} {
147 msg-checking "Checking for $function in $libs with $otherlibs..."
148 } else {
149 msg-checking "Checking for $function in $libs..."
150 }
151 set found 0
152 cc-with [list -libs $otherlibs] {
153 if {[cctest_function $function]} {
154 msg-result "none needed"
155 define lib_$function ""
156 incr found
157 } else {
158 foreach lib $libs {
159 cc-with [list -libs -l$lib] {
160 if {[cctest_function $function]} {
161 msg-result -l$lib
162 define lib_$function -l$lib
163 incr found
164 break
165 }
166 }
167 }
168 }
169 }
170 if {$found} {
171 define [feature-define-name $function]
172 } else {
173 msg-result "no"
174 }
175 return $found
176 }
177
178 if {![opt-bool internal-sqlite]} {
179 proc find_system_sqlite {} {
180
@@ -205,17 +219,17 @@
219 set sqlite-version [string cat "-D MINIMUM_SQLITE_VERSION=" [get-define MINIMUM_SQLITE_VERSION]]
220 lappend cmdline {*}[set sqlite-version]
221 set ok 1
222 set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
223 if {$err} {
224 configlog "Failed: [join $cmdline]"
225 if {[string length $result]>0} {configlog $result}
226 configlog "============"
227 set ok 0
228 } elseif {$::autosetup(debug)} {
229 configlog "Compiled OK: [join $cmdline]"
230 configlog "============"
231 }
232 if {!$ok} {
233 user-error "unable to compile SQLite compatibility test program"
234 }
235 set err [catch {exec-with-stderr ./conftest__} result errinfo]
@@ -230,498 +244,525 @@
244 test_system_sqlite
245
246 }
247
248 proc is_mingw {} {
249 return [expr {
250 [string match *mingw* [get-define host]] &&
251 ![file exists "/dev/null"]
252 }]
253 }
254
255 if {[is_mingw]} {
256 define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
257 define-append LIBS -lkernel32 -lws2_32
258 } else {
259 #
260 # NOTE: All platforms except MinGW should use the linenoise
261 # package. It is currently unsupported on Win32.
262 #
263 define USE_LINENOISE 1
264 }
265
266 if {[string match *-solaris* [get-define host]]} {
267 define-append EXTRA_CFLAGS {-D__EXTENSIONS__}
268 }
269
270 if {[opt-bool fossil-debug]} {
271 define CFLAGS {-g -O0 -Wall}
272 define-append CFLAGS -DFOSSIL_DEBUG
273 msg-result "Debugging support enabled"
274 }
275
276 if {[opt-bool no-opt]} {
277 define CFLAGS {-g -O0 -Wall}
278 msg-result "Builting without compiler optimization"
279 if {[opt-bool fossil-debug]} {
280 define-append CFLAGS -DFOSSIL_DEBUG
281 }
282 }
283
284 if {[opt-bool with-mman]} {
285 define-append EXTRA_CFLAGS -DUSE_MMAN_H
286 define USE_MMAN_H 1
287 msg-result "Enabling \"sys/mman.h\" support"
288 }
289
290 if {[opt-bool with-see]} {
291 define-append EXTRA_CFLAGS -DUSE_SEE
292 define USE_SEE 1
293 define SQLITE3_ORIGIN 1
294 msg-result "Enabling encryption support"
295 }
296
297 if {[opt-bool json]} {
298 # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
299 # is required in the CFLAGS because json*.c
300 # have #ifdef guards around the whole file without
301 # reading config.h first.
302 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
303 define FOSSIL_ENABLE_JSON
304 msg-result "JSON support enabled"
305 }
306
307 if {[opt-bool with-exec-rel-paths]} {
308 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS
309 define FOSSIL_ENABLE_EXEC_REL_PATHS
310 msg-result "Relative paths in external diff/gdiff enabled"
311 }
312
313 if {[opt-bool with-th1-docs]} {
314 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS
315 define FOSSIL_ENABLE_TH1_DOCS
316 msg-result "TH1 embedded documentation support enabled"
317 }
318
319 if {[opt-bool with-th1-hooks]} {
320 define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS
321 define FOSSIL_ENABLE_TH1_HOOKS
322 msg-result "TH1 hooks support enabled"
323 }
324
325 #if {[opt-bool markdown]} {
326 # # no-op. Markdown is now enabled by default.
327 # msg-result "Markdown support enabled"
328 #}
329
330 if {[opt-bool static]} {
331 # XXX: This will not work on all systems.
332 define-append EXTRA_LDFLAGS -static
333 msg-result "Trying to link statically"
334 } else {
335 define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
336 define FOSSIL_DYNAMIC_BUILD
337 }
338
339 # Check for libraries that need to be sorted out early
340 cc-check-function-in-lib iconv iconv
341
342 cc-check-function-in-lib sin m ;# must come before ssl check:
343 # https://fossil-scm.org/forum/forumpost/afcd42b7fd
344
345 # Helper for OpenSSL checking
346 proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto -lpthread}}} {
347 msg-checking "Checking for $msg..."
348 set rc 0
349 if {[is_mingw]} {
350 lappend libs -lgdi32 -lwsock32 -lcrypt32
351 }
352 if {[info exists ::zlib_lib]} {
353 lappend libs $::zlib_lib
354 }
355 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
356 if {[cc-check-includes openssl/ssl.h] && \
357 [cc-check-functions SSL_new]} {
358 incr rc
359 }
360 }
361 if {!$rc && ![is_mingw]} {
362 # On some systems, OpenSSL appears to require -ldl to link.
363 lappend libs -ldl
364 msg-quiet cc-with [list -cflags $cflags -libs $libs] {
365 if {[cc-check-includes openssl/ssl.h] && \
366 [cc-check-functions SSL_new]} {
367 incr rc
368 }
369 }
370 }
371 if {$rc} {
372 msg-result "ok"
373 return 1
374 } else {
375 msg-result "no"
376 return 0
377 }
378 }
379
380 #
381 # Check for zlib, using the given location if specified
382 #
383 proc handle-zlib {} {
384 set ::zlibpath [opt-val with-zlib]; # used by downstream tcl tests
385 if {$::zlibpath eq "tree"} {
386 set ::zlibdir [file dirname $::autosetup(dir)]/compat/zlib
387 if {![file isdirectory $::zlibdir]} {
388 user-error "The zlib in source tree directory does not exist"
389 } elseif { ([llength [glob -nocomplain -directory $::zlibdir libz*]] == 0) } {
390 user-error "With --with-zlib=tree, $::zlibdir must be configured and built first."
391 }
392 cc-with [list -cflags "-I$::zlibdir -L$::zlibdir"]
393 define-append EXTRA_CFLAGS -I$::zlibdir
394 define-append LIBS $::zlibdir/libz.a
395 set ::zlib_lib $::zlibdir/libz.a
396 msg-result "Using zlib in source tree"
397 } else {
398 set cftry {""}
399 set ldtry {""}
400 if {$::zlibpath ni {auto ""}} {
401 lappend cftry "-I$::zlibpath"
402 lappend cftry "-I$::zlibpath/include"
403 lappend ldtry "-L$::zlibpath"
404 lappend ldtry "-L$::zlibpath/lib"
405 }
406
407 # Reverse the list of tests so we check most-specific to least, else
408 # platform devel files will shadow local --with-zlib overrides.
409 foreach c [lreverse $cftry] {
410 if {[cc-with [list -cflags $c] {cc-check-includes zlib.h}]} {
411 if {$c eq ""} {
412 msg-result "Found zlib.h in default include path"
413 } else {
414 define-append EXTRA_CFLAGS "$c"
415 msg-result "Found zlib.h via $c"
416 }
417 set cfound $c
418 break
419 }
420 }
421 if {![info exists cfound]} {
422 user-error "zlib.h not found; either install it or specify its location via --with-zlib"
423 }
424 foreach lcheck [lreverse $ldtry] {
425 if {[cc-with [list -cflags "$cfound $lcheck"] {check-function-in-lib inflateEnd z}]} {
426 if {$lcheck eq ""} {
427 msg-result "Linked to zlib via default library path"
428 } else {
429 define-append EXTRA_LDFLAGS "$lcheck"
430 msg-result "Linked to zlib via $lcheck"
431 }
432 if {![check-function-in-lib compressBound z]} {
433 puts "Notice: disabling zlib compression in the SQL shell"
434 define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
435 }
436 break
437 }
438 }
439 set ::zlib_lib -lz
440 }
441 }; # handle-zlib
442 handle-zlib
443
444 #
445 # Handle the --with-openssl flag and, incidentally, update @LIBS@ for
446 # zlib if openssl is _not_ used (if it is, we get zlib via libssl).
447 #
448 # This function should be called as late as possible in the configure
449 # script to avoid that its updates to @LIBS@ break tests which follow
450 # it when a custom local build of openssl is used, as discussed in
451 # <https://fossil-scm.org/forum/forumpost/15e3d9cdc137030c>.
452 #
453 proc handle-with-openssl {} {
454 set ssldirs [opt-val with-openssl]
455 if {$ssldirs ne "none"} {
456 set found 0
457 if {$ssldirs eq "tree"} {
458 set ssldir [file dirname $::autosetup(dir)]/compat/openssl
459 if {![file isdirectory $ssldir]} {
460 user-error "The OpenSSL in source tree directory does not exist"
461 }
462 set msg "openssl in $ssldir"
463 set cflags "-I$ssldir/include"
464 set ldflags "-L$ssldir"
465 set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
466 set found [check-for-openssl "openssl in source tree" "$cflags $ldflags" $ssllibs]
467 } else {
468 if {$ssldirs in {auto ""}} {
469 catch {
470 # TODO?: use autosetup's pkg-config support
471 set cflags [exec pkg-config openssl --cflags-only-I]
472 set ldflags [exec pkg-config openssl --libs-only-L]
473 set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
474 } msg
475 if {!$found} {
476 set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \
477 /usr/pkg /usr/local /usr /usr/local/opt/openssl \
478 /opt/homebrew/opt/openssl"
479 }
480 }
481 if {!$found} {
482 foreach dir $ssldirs {
483 if {$dir eq ""} {
484 set msg "system openssl"
485 set cflags ""
486 set ldflags ""
487 } else {
488 set msg "openssl in $dir"
489 set cflags "-I$dir/include"
490 if {[file readable $dir/libssl.a]} {
491 set ldflags -L$dir
492 } elseif {[file readable $dir/lib/libssl.a]} {
493 set ldflags -L$dir/lib
494 } elseif {[file isdir $dir/lib]} {
495 set ldflags "-L$dir -L$dir/lib"
496 } else {
497 set ldflags -L$dir
498 }
499 }
500 if {[check-for-openssl $msg "$cflags $ldflags"]} {
501 incr found
502 break
503 }
504 if {$dir ne ""} {
505 set ldflags ""
506 set msg "static build of openssl in $dir"
507 set ssllibs "$dir/libssl.a $dir/libcrypto.a -lpthread"
508 if {[check-for-openssl $msg "$cflags $ldflags" $ssllibs]} {
509 incr found
510 break
511 }
512 }
513 }
514 }
515 }
516 if {$found} {
517 define FOSSIL_ENABLE_SSL
518 define-append EXTRA_CFLAGS $cflags
519 define-append EXTRA_LDFLAGS $ldflags
520 if {[info exists ssllibs]} {
521 define-append LIBS $ssllibs
522 } else {
523 define-append LIBS -lssl -lcrypto
524 }
525 if {[info exists ::zlib_lib]} {
526 define-append LIBS $::zlib_lib
527 }
528 if {[is_mingw]} {
529 define-append LIBS -lgdi32 -lwsock32 -lcrypt32
530 }
531 msg-result "HTTPS support enabled"
532
533 # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
534 if {[string match *-darwin* [get-define host]]} {
535 if {[cctest -cflags {-Wdeprecated-declarations}]} {
536 define-append EXTRA_CFLAGS -Wdeprecated-declarations
537 }
538 }
539 } else {
540 user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
541 }
542 } else {
543 if {[info exists ::zlib_lib]} {
544 define-append LIBS $::zlib_lib
545 }
546 }
547 }; # handle-with-openssl
548
549 #
550 # CFLAGS_INCLUDE is ONLY for -I... flags and their order is
551 # significant so that --with-sqlite=PATH's header can shadow our
552 # own. <s>One caveat with this is that we cannot point
553 # --with-sqlite=PATH to the root of sqlite3's own build tree because
554 # that dir has a config.h which ends up shadowing src/config.h,
555 # breaking our build.</s> (That is no longer true: that that config.h
556 # was renamed to sqlite_cfg.h at some point.)
557 #
558 define CFLAGS_INCLUDE {}
559
560 ########################################################################
561 # --with-sqlite=PATH checks for the first it finds of the following...
562 # - PATH/sqlite3.c and PATH/sqlite3.h
563 # - PATH/sqlite3.o (and assumes sqlite3.h is with it)
564 # - PATH/lib/libsqlite3* and PATH/include/sqlite3.h
565 proc handle-with-sqlite {} {
566 set sq3path [opt-val with-sqlite]
567 define SQLITE3_SRC.2 {}
568 define SQLITE3_OBJ.2 {}
569 define SQLITE3_SHELL_SRC.2 {$(SQLITE3_SHELL_SRC.0)}
570 if {$sq3path in {tree ""}} {
571 msg-result "Using sqlite3.c from this source tree."
572 } else {
573 # SQLITE3_ORIGIN:
574 # 0 = local source tree
575 # 1 = use external lib or sqlite3.o
576 # 2 = use external sqlite3.c and (if found) shell.c
577 define USE_SYSTEM_SQLITE 1
578 define SQLITE3_ORIGIN 2
579 if {$sq3path != "auto"} {
580 if {([file exists $sq3path/sqlite3.c]) &&
581 ([file exists $sq3path/sqlite3.h]) } {
582 # Prefer sqlite3.[ch] if found.
583 define SQLITE3_SRC.2 $sq3path/sqlite3.c
584 define SQLITE3_OBJ.2 {$(SQLITE3_OBJ.0)}
585 define USE_SYSTEM_SQLITE 2
586 define SQLITE3_ORIGIN 2
587 if {[file exists $sq3path/shell.c]} {
588 define SQLITE3_SHELL_SRC.2 $sq3path/shell.c
589 }
590 define-append CFLAGS_INCLUDE -I$sq3path
591 define-append EXTRA_LDFLAGS -lpthread
592 # ^^^ additional -lXXX flags are conservative estimates
593 msg-result "Using sqlite3.c and sqlite3.h from $sq3path"
594 } elseif {[file exists $sq3path/sqlite3.o]} {
595 # Use sqlite3.o if found.
596 define SQLITE3_OBJ.2 $sq3path/sqlite3.o
597 define-append CFLAGS_INCLUDE -I$sq3path
598 define-append EXTRA_LDFLAGS $sq3path/sqlite3.o -lpthread
599 # ^^^ additional -lXXX flags are conservative estimates
600 msg-result "Using sqlite3.o from $sq3path"
601 } elseif { ([llength [glob -nocomplain -directory $sq3path/lib libsqlite3*]] != 0) \
602 && ([file exists $sq3path/include/sqlite3.h]) } {
603 # e.g. --with-sqlite=/usr/local. Try $sq3path/lib/libsqlite3*
604 # and $sq3path/include/sqlite3.h
605 define-append CFLAGS_INCLUDE -I$sq3path/include
606 define-append EXTRA_LDFLAGS -L$sq3path/lib -lsqlite3 -lpthread
607 # ^^^ additional -lXXX flags are conservative estimates
608 msg-result "Using -lsqlite3 from $sq3path"
609 } else {
610 # Assume $sq3path holds both the lib and header
611 cc-with [list -cflags "-I$sq3path -L$sq3path"]
612 define-append CFLAGS_INCLUDE -I$sq3path
613 define-append EXTRA_LDFLAGS -L$sq3path -lsqlite3 -lpthread
614 # ^^^ additional -lXXX flags are conservative estimates
615 msg-result "Using -lsqlite3 from $sq3path"
616 }
617 } elseif {![cc-check-includes sqlite3.h] || ![check-function-in-lib sqlite3_open_v2 sqlite3]} {
618 user-error "libsqlite3 not found please install it or specify the location with --with-sqlite"
619 }
620 }
621 }; # handle-with-sqlite
622 handle-with-sqlite
623 define-append CFLAGS_INCLUDE {-I. -I$(SRCDIR) -I$(SRCDIR_extsrc)}; # must be after handle-with-sqlite
624
625 #
626 # Handle the --with-tcl flag.
627 #
628 proc handle-with-tcl {} {
629 set tclpath [opt-val with-tcl]
630 if {$tclpath eq ""} {
631 return
632 }
633 set tclprivatestubs [opt-bool with-tcl-private-stubs]
634 # Note parse-tclconfig-sh is in autosetup/local.tcl
635 if {$tclpath eq "1"} {
636 set tcldir [file dirname $::autosetup(dir)]/compat/tcl-8.6
637 if {$tclprivatestubs} {
638 set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
639 set tclconfig(TCL_VERSION) {Private Stubs}
640 set tclconfig(TCL_PATCH_LEVEL) {}
641 set tclconfig(TCL_PREFIX) $tcldir
642 set tclconfig(TCL_LD_FLAGS) { }
643 } else {
644 # Use the system Tcl. Look in some likely places.
645 array set tclconfig [parse-tclconfig-sh \
646 $tcldir/unix $tcldir/win \
647 /usr /usr/local /usr/share /opt/local]
648 set msg "on your system"
649 }
650 } else {
651 array set tclconfig [parse-tclconfig-sh $tclpath]
652 set msg "at $tclpath"
653 }
654 if {[opt-bool static]} {
655 set tclconfig(TCL_LD_FLAGS) { }
656 }
657 if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
658 user-error "Cannot find Tcl $msg"
659 }
660 set tclstubs [opt-bool with-tcl-stubs]
661 if {$tclprivatestubs} {
662 define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
663 define USE_TCL_STUBS
664 } elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
665 set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
666 define FOSSIL_ENABLE_TCL_STUBS
667 define USE_TCL_STUBS
668 } else {
669 set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
670 }
671 set cflags $tclconfig(TCL_INCLUDE_SPEC)
672 if {!$tclprivatestubs} {
673 set foundtcl 0; # Did we find a working Tcl library?
674 cc-with [list -cflags $cflags -libs $libs] {
675 if {$tclstubs} {
676 if {[cc-check-functions Tcl_InitStubs]} {
677 set foundtcl 1
678 }
679 } else {
680 if {[cc-check-functions Tcl_CreateInterp]} {
681 set foundtcl 1
682 }
683 }
684 }
685 if {!$foundtcl && [string match *-lieee* $libs]} {
686 # On some systems, using "-lieee" from TCL_LIB_SPEC appears
687 # to cause issues.
688 msg-result "Removing \"-lieee\" and retrying for Tcl..."
689 set libs [string map [list -lieee ""] $libs]
690 cc-with [list -cflags $cflags -libs $libs] {
691 if {$tclstubs} {
692 if {[cc-check-functions Tcl_InitStubs]} {
693 set foundtcl 1
694 }
695 } else {
696 if {[cc-check-functions Tcl_CreateInterp]} {
697 set foundtcl 1
698 }
699 }
700 }
701 }
702 if {!$foundtcl && ![string match *-lpthread* $libs]} {
703 # On some systems, TCL_LIB_SPEC appears to be missing
704 # "-lpthread". Try adding it.
705 msg-result "Adding \"-lpthread\" and retrying for Tcl..."
706 set libs "$libs -lpthread"
707 cc-with [list -cflags $cflags -libs $libs] {
708 if {$tclstubs} {
709 if {[cc-check-functions Tcl_InitStubs]} {
710 set foundtcl 1
711 }
712 } else {
713 if {[cc-check-functions Tcl_CreateInterp]} {
714 set foundtcl 1
715 }
716 }
717 }
718 }
719 if {!$foundtcl} {
720 if {$tclstubs} {
721 user-error "Cannot find a usable Tcl stubs library $msg"
722 } else {
723 user-error "Cannot find a usable Tcl library $msg"
724 }
725 }
726 }
727 set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
728 msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
729 if {!$tclprivatestubs} {
730 define-append LIBS $libs
731 }
732 define-append EXTRA_CFLAGS $cflags
733 define-append CFLAGS $cflags
734 if {[info exists ::zlibpath] && $::zlibpath eq "tree"} {
735 #
736 # NOTE: When using zlib in the source tree, prevent Tcl from
737 # pulling in the system one.
738 #
739 set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
740 $tclconfig(TCL_LD_FLAGS)]
741 }
742 #
743 # NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
744 # be checked for near the bottom of this file.
745 #
746 set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
747 $tclconfig(TCL_LD_FLAGS)]
748 define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
749 define FOSSIL_ENABLE_TCL
750 }; # handle-with-tcl
751 handle-with-tcl
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
752
753 # Network functions require libraries on some systems
754 cc-check-function-in-lib gethostbyname nsl
755 if {![cc-check-function-in-lib socket {socket network}]} {
756 # Last resort, may be Windows
757 if {[is_mingw]} {
758 define-append LIBS -lwsock32
759 }
760 }
761
762 # Some systems (ex: SunOS) require -lrt in order to use nanosleep
763 cc-check-function-in-lib nanosleep rt
764
765 # The SMTP module requires special libraries and headers for MX DNS
766 # record lookups and such.
767 cc-check-includes arpa/nameser.h
768 cc-include-needs bind/resolv.h netinet/in.h
@@ -732,11 +773,11 @@
773 [cc-check-function-in-lib __ns_name_uncompress {bind resolv}]) &&
774 ([cc-check-function-in-lib ns_parserr {bind resolv}] ||
775 [cc-check-function-in-lib __ns_parserr {bind resolv}]) &&
776 ([cc-check-function-in-lib res_query {bind resolv}] ||
777 [cc-check-function-in-lib __res_query {bind resolv}]))} {
778 msg-result "WARNING: SMTP feature will not be able to look up local MX."
779 }
780 cc-check-function-in-lib res_9_ns_initparse resolv
781
782 # Other nonstandard function checks
783 cc-check-functions utime
@@ -744,15 +785,15 @@
785 cc-check-functions strchrnul
786 cc-check-functions pledge
787 cc-check-functions backtrace
788
789 # Termux on Android adds "getpass(char *)" to unistd.h, so check this so we
790 # guard against including it again; use cctest as cc-check-functions and
791 # cctest_function check for "getpass()" with no args and fail
792 if {[cctest -link 1 -includes {unistd.h} -code "getpass(0);"]} {
793 define FOSSIL_HAVE_GETPASS 1
794 msg-result "Found getpass() with unistd.h"
795 }
796
797 # Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
798 if {![cc-check-functions getloadavg] ||
799 ![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
@@ -760,44 +801,43 @@
801 msg-result "Load average support unavailable"
802 }
803
804 # Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
805 if {![cc-check-functions getpassphrase]} {
806 # Haiku needs this
807 cc-check-function-in-lib getpass bsd
808 }
 
809
810 # Check for the FuseFS library
811 if {[opt-bool fusefs]} {
812 if {[opt-bool static]} {
813 msg-result "FuseFS support disabled due to -static"
814 } elseif {[cc-check-function-in-lib fuse_mount fuse]} {
815 define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
816 define FOSSIL_HAVE_FUSEFS 1
817 msg-result "FuseFS support enabled"
818 }
819 }
820
821 ########################################################################
822 # Checks the compiler for compile_commands.json support.
823 #
824 # Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes"
825 # if supported, "no" if not.
826 proc check-compile-commands {} {
827 msg-checking "compile_commands.json support... "
828 if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
829 # This test reportedly incorrectly succeeds on one of
830 # Martin G.'s older systems.
831 msg-result "compiler supports compile_commands.json"
832 define MAKE_COMPILATION_DB yes
833 return 1
834 } else {
835 msg-result "compiler does not support compile_commands.json"
836 define MAKE_COMPILATION_DB no
837 return 0
838 }
839 }
840
841 define MAKE_COMPILATION_DB no
842 if {!$outOfTreeBuild} {
843 if {[opt-bool compile-commands]} {
@@ -814,40 +854,114 @@
854 # Add -fsanitize compile and link options late: we don't want the C
855 # checks above to run with those sanitizers enabled. It can not only
856 # be pointless, it can actually break correct tests.
857 set fsan [opt-val with-sanitizer]
858 if {[string length $fsan]} {
859 define-append EXTRA_CFLAGS -fsanitize=$fsan
860 define-append EXTRA_LDFLAGS -fsanitize=$fsan
861 if {[string first "undefined" $fsan] != -1} {
862 # We need to link with libubsan if we're compiling under
863 # GCC with -fsanitize=undefined.
864 cc-check-function-in-lib __ubsan_handle_add_overflow ubsan
865 }
866 }
867
868 # Finally, append libraries that must be last. This matters more on some
869 # OSes than others, but is most broadly required for static linking.
870 if {[check-function-in-lib dlopen dl]} {
871 # Some platforms (*BSD) have the dl functions already in libc and no libdl.
872 # In such case we can link directly without -ldl.
873 define-append LIBS [get-define lib_dlopen]
874 }
875 if {[opt-bool static]} {
876 # Linux can only infer the dependency on pthread from OpenSSL when
877 # doing dynamic linkage.
878 define-append LIBS -lpthread
879 }
880
881
882 ########################################################################
883 # @proj-check-emsdk
884 #
885 # Emscripten is used for doing in-tree builds of web-based WASM stuff,
886 # as opposed to WASI-based WASM or WASM binaries we import from other
887 # places. This is only set up for Unix-style OSes and is untested
888 # anywhere but Linux. Requires that the --with-emsdk flag be
889 # registered with autosetup.
890 #
891 # It looks for the SDK in the location specified by --with-emsdk.
892 # Values of "" or "auto" mean to check for the environment var EMSDK
893 # (which gets set by the emsdk_env.sh script from the SDK) or that
894 # same var passed to configure.
895 #
896 # If the given directory is found, it expects to find emsdk_env.sh in
897 # that directory, as well as the emcc compiler somewhere under there.
898 #
899 # If the --with-emsdk flag is explicitly provided and the SDK is not
900 # found then a fatal error is generated, otherwise failure to find the
901 # SDK is not fatal.
902 #
903 # Defines the following:
904 #
905 # - EMSDK_HOME = top dir of the emsdk or "".
906 # - EMSDK_ENV_SH = path to EMSDK_HOME/emsdk_env.sh or ""
907 # - BIN_EMCC = $EMSDK_HOME/upstream/emscripten/emcc or ""
908 # - HAVE_EMSDK = 0 or 1 (this function's return value)
909 #
910 # Returns 1 if EMSDK_ENV_SH is found, else 0. If EMSDK_HOME is not empty
911 # but BIN_EMCC is then emcc was not found in the EMSDK_HOME, in which
912 # case we have to rely on the fact that sourcing $EMSDK_ENV_SH from a
913 # shell will add emcc to the $PATH.
914 proc proj-check-emsdk {} {
915 set emsdkHome [opt-val with-emsdk]
916 define EMSDK_HOME ""
917 define EMSDK_ENV_SH ""
918 define BIN_EMCC ""
919 set hadValue [llength $emsdkHome]
920 msg-checking "Emscripten SDK? "
921 if {$emsdkHome in {"" "auto"}} {
922 # Check the environment. $EMSDK gets set by sourcing emsdk_env.sh.
923 set emsdkHome [get-env EMSDK ""]
924 }
925 set rc 0
926 if {$emsdkHome ne ""} {
927 define EMSDK_HOME $emsdkHome
928 set emsdkEnv "$emsdkHome/emsdk_env.sh"
929 if {[file exists $emsdkEnv]} {
930 msg-result "$emsdkHome"
931 define EMSDK_ENV_SH $emsdkEnv
932 set rc 1
933 set emcc "$emsdkHome/upstream/emscripten/emcc"
934 if {[file exists $emcc]} {
935 define BIN_EMCC $emcc
936 }
937 } else {
938 msg-result "emsdk_env.sh not found in $emsdkHome"
939 }
940 } else {
941 msg-result "not found"
942 }
943 if {$hadValue && 0 == $rc} {
944 # Fail if it was explicitly requested but not found
945 proj-fatal "Cannot find the Emscripten SDK"
946 }
947 define HAVE_EMSDK $rc
948 return $rc
949 }
950
951 if {[proj-check-emsdk]} {
952 define EMCC_WRAPPER $::autosetup(dir)/../tools/emcc.sh
953 define EMCC_OPT [get-env EMCC_OPT "-Oz"]; # optional flags to pass to emcc
954 make-template tools/emcc.sh.in
955 catch {exec chmod u+x tools/emcc.sh}
956 } else {
957 define EMCC_WRAPPER ""
958 define EMCC_OPT ""
959 catch {exec rm -f tools/emcc.sh}
960 }
961
962 handle-with-openssl
963
964 # Tag container builds with a prefix of the checkin ID of the version
965 # of Fossil each one contains. This not only allows multiple images
966 # to coexist and multiple containers to be created unamgiguosly from
967 # them, it also changes the URL we fetch the source tarball from, so
968
969 DDED extsrc/linenoise-win32.c
--- a/extsrc/linenoise-win32.c
+++ b/extsrc/linenoise-win32.c
@@ -0,0 +1,379 @@
1
+
2
+/* this code is not standalone
3
+ * it is included into linenoise.c
4
+ * for windows.
5
+ * It is deliberately kept separate so that
6
+ * applications that have no need for windows
7
+ * support can omit this
8
+ */
9
+static DWORD orig_consolemode = 0;
10
+
11
+static int flushOutput(struct current *current);
12
+static void outputNewline(struct current *current);
13
+
14
+static void refreshStart(struct current *current)
15
+{
16
+ (void)current;
17
+}
18
+
19
+static void refreshEnd(struct current *current)
20
+{
21
+ (void)current;
22
+}
23
+
24
+static void refreshStartChars(struct current *current)
25
+{
26
+ assert(current->output == NULL);
27
+ /* We accumulate all output here */
28
+ current->output = sb_alloc();
29
+#ifdef USE_UTF8
30
+ current->ubuflen = 0;
31
+#endif
32
+}
33
+
34
+static void refreshNewline(struct current *current)
35
+{
36
+ DRL("<nl>");
37
+ outputNewline(current);
38
+}
39
+
40
+static void refreshEndChars(struct current *current)
41
+{
42
+ assert(current->output);
43
+ flushOutput(current);
44
+ sb_free(current->output);
45
+ current->output = NULL;
46
+}
47
+
48
+static int enableRawMode(struct current *current) {
49
+ DWORD n;
50
+ INPUT_RECORD irec;
51
+
52
+ current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
53
+ current->inh = GetStdHandle(STD_INPUT_HANDLE);
54
+
55
+ if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
56
+ return -1;
57
+ }
58
+ if (getWindowSize(current) != 0) {
59
+ return -1;
60
+ }
61
+ if (GetConsoleMode(current->inh, &orig_consolemode)) {
62
+ SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
63
+ }
64
+#ifdef USE_UTF8
65
+ /* XXX is this the right thing to do? */
66
+ SetConsoleCP(65001);
67
+#endif
68
+ return 0;
69
+}
70
+
71
+static void disableRawMode(struct current *current)
72
+{
73
+ SetConsoleMode(current->inh, orig_consolemode);
74
+}
75
+
76
+void linenoiseClearScreen(void)
77
+{
78
+ /* XXX: This is ugly. Should just have the caller pass a handle */
79
+ struct current current;
80
+
81
+ current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
82
+
83
+ if (getWindowSize(&current) == 0) {
84
+ COORD topleft = { 0, 0 };
85
+ DWORD n;
86
+
87
+ FillConsoleOutputCharacter(current.outh, ' ',
88
+ current.cols * current.rows, topleft, &n);
89
+ FillConsoleOutputAttribute(current.outh,
90
+ FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
91
+ current.cols * current.rows, topleft, &n);
92
+ SetConsoleCursorPosition(current.outh, topleft);
93
+ }
94
+}
95
+
96
+static void cursorToLeft(struct current *current)
97
+{
98
+ COORD pos;
99
+ DWORD n;
100
+
101
+ pos.X = 0;
102
+ pos.Y = (SHORT)current->y;
103
+
104
+ FillConsoleOutputAttribute(current->outh,
105
+ FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
106
+ current->x = 0;
107
+}
108
+
109
+#ifdef USE_UTF8
110
+static void flush_ubuf(struct current *current)
111
+{
112
+ COORD pos;
113
+ DWORD nwritten;
114
+ pos.Y = (SHORT)current->y;
115
+ pos.X = (SHORT)current->x;
116
+ SetConsoleCursorPosition(current->outh, pos);
117
+ WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
118
+ current->x += current->ubufcols;
119
+ current->ubuflen = 0;
120
+ current->ubufcols = 0;
121
+}
122
+
123
+static void add_ubuf(struct current *current, int ch)
124
+{
125
+ /* This code originally by: Author: Mark E. Davis, 1994. */
126
+ static const int halfShift = 10; /* used for shifting by 10 bits */
127
+
128
+ static const DWORD halfBase = 0x0010000UL;
129
+ static const DWORD halfMask = 0x3FFUL;
130
+
131
+ #define UNI_SUR_HIGH_START 0xD800
132
+ #define UNI_SUR_HIGH_END 0xDBFF
133
+ #define UNI_SUR_LOW_START 0xDC00
134
+ #define UNI_SUR_LOW_END 0xDFFF
135
+
136
+ #define UNI_MAX_BMP 0x0000FFFF
137
+
138
+ if (ch > UNI_MAX_BMP) {
139
+ /* convert from unicode to utf16 surrogate pairs
140
+ * There is always space for one extra word in ubuf
141
+ */
142
+ ch -= halfBase;
143
+ current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
144
+ current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
145
+ }
146
+ else {
147
+ current->ubuf[current->ubuflen++] = ch;
148
+ }
149
+ current->ubufcols += utf8_width(ch);
150
+ if (current->ubuflen >= UBUF_MAX_CHARS) {
151
+ flush_ubuf(current);
152
+ }
153
+}
154
+#endif
155
+
156
+static int flushOutput(struct current *current)
157
+{
158
+ const char *pt = sb_str(current->output);
159
+ int len = sb_len(current->output);
160
+
161
+#ifdef USE_UTF8
162
+ /* convert utf8 in current->output into utf16 in current->ubuf
163
+ */
164
+ while (len) {
165
+ int ch;
166
+ int n = utf8_tounicode(pt, &ch);
167
+
168
+ pt += n;
169
+ len -= n;
170
+
171
+ add_ubuf(current, ch);
172
+ }
173
+ flush_ubuf(current);
174
+#else
175
+ DWORD nwritten;
176
+ COORD pos;
177
+
178
+ pos.Y = (SHORT)current->y;
179
+ pos.X = (SHORT)current->x;
180
+
181
+ SetConsoleCursorPosition(current->outh, pos);
182
+ WriteConsoleA(current->outh, pt, len, &nwritten, 0);
183
+
184
+ current->x += len;
185
+#endif
186
+
187
+ sb_clear(current->output);
188
+
189
+ return 0;
190
+}
191
+
192
+static int outputChars(struct current *current, const char *buf, int len)
193
+{
194
+ if (len < 0) {
195
+ len = strlen(buf);
196
+ }
197
+ assert(current->output);
198
+
199
+ sb_append_len(current->output, buf, len);
200
+
201
+ return 0;
202
+}
203
+
204
+static void outputNewline(struct current *current)
205
+{
206
+ /* On the last row output a newline to force a scroll */
207
+ if (current->y + 1 == current->rows) {
208
+ outputChars(current, "\n", 1);
209
+ }
210
+ flushOutput(current);
211
+ current->x = 0;
212
+ current->y++;
213
+}
214
+
215
+static void setOutputHighlight(struct current *current, const int *props, int nprops)
216
+{
217
+ int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
218
+ int bold = 0;
219
+ int reverse = 0;
220
+ int i;
221
+
222
+ for (i = 0; i < nprops; i++) {
223
+ switch (props[i]) {
224
+ case 0:
225
+ colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
226
+ bold = 0;
227
+ reverse = 0;
228
+ break;
229
+ case 1:
230
+ bold = FOREGROUND_INTENSITY;
231
+ break;
232
+ case 7:
233
+ reverse = 1;
234
+ break;
235
+ case 30:
236
+ colour = 0;
237
+ break;
238
+ case 31:
239
+ colour = FOREGROUND_RED;
240
+ break;
241
+ case 32:
242
+ colour = FOREGROUND_GREEN;
243
+ break;
244
+ case 33:
245
+ colour = FOREGROUND_RED | FOREGROUND_GREEN;
246
+ break;
247
+ case 34:
248
+ colour = FOREGROUND_BLUE;
249
+ break;
250
+ case 35:
251
+ colour = FOREGROUND_RED | FOREGROUND_BLUE;
252
+ break;
253
+ case 36:
254
+ colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
255
+ break;
256
+ case 37:
257
+ colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
258
+ break;
259
+ }
260
+ }
261
+
262
+ flushOutput(current);
263
+
264
+ if (reverse) {
265
+ SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
266
+ }
267
+ else {
268
+ SetConsoleTextAttribute(current->outh, colour | bold);
269
+ }
270
+}
271
+
272
+static void eraseEol(struct current *current)
273
+{
274
+ COORD pos;
275
+ DWORD n;
276
+
277
+ pos.X = (SHORT) current->x;
278
+ pos.Y = (SHORT) current->y;
279
+
280
+ FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
281
+}
282
+
283
+static void setCursorXY(struct current *current)
284
+{
285
+ COORD pos;
286
+
287
+ pos.X = (SHORT) current->x;
288
+ pos.Y = (SHORT) current->y;
289
+
290
+ SetConsoleCursorPosition(current->outh, pos);
291
+}
292
+
293
+
294
+static void setCursorPos(struct current *current, int x)
295
+{
296
+ current->x = x;
297
+ setCursorXY(current);
298
+}
299
+
300
+static void cursorUp(struct current *current, int n)
301
+{
302
+ current->y -= n;
303
+ setCursorXY(current);
304
+}
305
+
306
+static void cursorDown(struct current *current, int n)
307
+{
308
+ current->y += n;
309
+ setCursorXY(current);
310
+}
311
+
312
+static int fd_read(struct current *current)
313
+{
314
+ while (1) {
315
+ INPUT_RECORD irec;
316
+ DWORD n;
317
+ if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
318
+ break;
319
+ }
320
+ if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
321
+ break;
322
+ }
323
+ if (irec.EventType == KEY_EVENT) {
324
+ KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
325
+ if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
326
+ if (k->dwControlKeyState & ENHANCED_KEY) {
327
+ switch (k->wVirtualKeyCode) {
328
+ case VK_LEFT:
329
+ return SPECIAL_LEFT;
330
+ case VK_RIGHT:
331
+ return SPECIAL_RIGHT;
332
+ case VK_UP:
333
+ return SPECIAL_UP;
334
+ case VK_DOWN:
335
+ return SPECIAL_DOWN;
336
+ case VK_INSERT:
337
+ return SPECIAL_INSERT;
338
+ case VK_DELETE:
339
+ return SPECIAL_DELETE;
340
+ case VK_HOME:
341
+ return SPECIAL_HOME;
342
+ case VK_END:
343
+ return SPECIAL_END;
344
+ case VK_PRIOR:
345
+ return SPECIAL_PAGE_UP;
346
+ case VK_NEXT:
347
+ return SPECIAL_PAGE_DOWN;
348
+ case VK_RETURN:
349
+ return k->uChar.UnicodeChar;
350
+ }
351
+ }
352
+ /* Note that control characters are already translated in AsciiChar */
353
+ else if (k->wVirtualKeyCode == VK_CONTROL)
354
+ continue;
355
+ else {
356
+ return k->uChar.UnicodeChar;
357
+ }
358
+ }
359
+ }
360
+ }
361
+ return -1;
362
+}
363
+
364
+static int getWindowSize(struct current *current)
365
+{
366
+ CONSOLE_SCREEN_BUFFER_INFO info;
367
+ if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
368
+ return -1;
369
+ }
370
+ current->cols = info.dwSize.X;
371
+ current->rows = info.dwSize.Y;
372
+ if (current->cols <= 0 || current->rows <= 0) {
373
+ current->cols = 80;
374
+ return -1;
375
+ }
376
+ current->y = info.dwCursorPosition.Y;
377
+ current->x = info.dwCursorPosition.X;
378
+ return 0;
379
+}
--- a/extsrc/linenoise-win32.c
+++ b/extsrc/linenoise-win32.c
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/extsrc/linenoise-win32.c
+++ b/extsrc/linenoise-win32.c
@@ -0,0 +1,379 @@
1
2 /* this code is not standalone
3 * it is included into linenoise.c
4 * for windows.
5 * It is deliberately kept separate so that
6 * applications that have no need for windows
7 * support can omit this
8 */
9 static DWORD orig_consolemode = 0;
10
11 static int flushOutput(struct current *current);
12 static void outputNewline(struct current *current);
13
14 static void refreshStart(struct current *current)
15 {
16 (void)current;
17 }
18
19 static void refreshEnd(struct current *current)
20 {
21 (void)current;
22 }
23
24 static void refreshStartChars(struct current *current)
25 {
26 assert(current->output == NULL);
27 /* We accumulate all output here */
28 current->output = sb_alloc();
29 #ifdef USE_UTF8
30 current->ubuflen = 0;
31 #endif
32 }
33
34 static void refreshNewline(struct current *current)
35 {
36 DRL("<nl>");
37 outputNewline(current);
38 }
39
40 static void refreshEndChars(struct current *current)
41 {
42 assert(current->output);
43 flushOutput(current);
44 sb_free(current->output);
45 current->output = NULL;
46 }
47
48 static int enableRawMode(struct current *current) {
49 DWORD n;
50 INPUT_RECORD irec;
51
52 current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
53 current->inh = GetStdHandle(STD_INPUT_HANDLE);
54
55 if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
56 return -1;
57 }
58 if (getWindowSize(current) != 0) {
59 return -1;
60 }
61 if (GetConsoleMode(current->inh, &orig_consolemode)) {
62 SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
63 }
64 #ifdef USE_UTF8
65 /* XXX is this the right thing to do? */
66 SetConsoleCP(65001);
67 #endif
68 return 0;
69 }
70
71 static void disableRawMode(struct current *current)
72 {
73 SetConsoleMode(current->inh, orig_consolemode);
74 }
75
76 void linenoiseClearScreen(void)
77 {
78 /* XXX: This is ugly. Should just have the caller pass a handle */
79 struct current current;
80
81 current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
82
83 if (getWindowSize(&current) == 0) {
84 COORD topleft = { 0, 0 };
85 DWORD n;
86
87 FillConsoleOutputCharacter(current.outh, ' ',
88 current.cols * current.rows, topleft, &n);
89 FillConsoleOutputAttribute(current.outh,
90 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
91 current.cols * current.rows, topleft, &n);
92 SetConsoleCursorPosition(current.outh, topleft);
93 }
94 }
95
96 static void cursorToLeft(struct current *current)
97 {
98 COORD pos;
99 DWORD n;
100
101 pos.X = 0;
102 pos.Y = (SHORT)current->y;
103
104 FillConsoleOutputAttribute(current->outh,
105 FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
106 current->x = 0;
107 }
108
109 #ifdef USE_UTF8
110 static void flush_ubuf(struct current *current)
111 {
112 COORD pos;
113 DWORD nwritten;
114 pos.Y = (SHORT)current->y;
115 pos.X = (SHORT)current->x;
116 SetConsoleCursorPosition(current->outh, pos);
117 WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
118 current->x += current->ubufcols;
119 current->ubuflen = 0;
120 current->ubufcols = 0;
121 }
122
123 static void add_ubuf(struct current *current, int ch)
124 {
125 /* This code originally by: Author: Mark E. Davis, 1994. */
126 static const int halfShift = 10; /* used for shifting by 10 bits */
127
128 static const DWORD halfBase = 0x0010000UL;
129 static const DWORD halfMask = 0x3FFUL;
130
131 #define UNI_SUR_HIGH_START 0xD800
132 #define UNI_SUR_HIGH_END 0xDBFF
133 #define UNI_SUR_LOW_START 0xDC00
134 #define UNI_SUR_LOW_END 0xDFFF
135
136 #define UNI_MAX_BMP 0x0000FFFF
137
138 if (ch > UNI_MAX_BMP) {
139 /* convert from unicode to utf16 surrogate pairs
140 * There is always space for one extra word in ubuf
141 */
142 ch -= halfBase;
143 current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
144 current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
145 }
146 else {
147 current->ubuf[current->ubuflen++] = ch;
148 }
149 current->ubufcols += utf8_width(ch);
150 if (current->ubuflen >= UBUF_MAX_CHARS) {
151 flush_ubuf(current);
152 }
153 }
154 #endif
155
156 static int flushOutput(struct current *current)
157 {
158 const char *pt = sb_str(current->output);
159 int len = sb_len(current->output);
160
161 #ifdef USE_UTF8
162 /* convert utf8 in current->output into utf16 in current->ubuf
163 */
164 while (len) {
165 int ch;
166 int n = utf8_tounicode(pt, &ch);
167
168 pt += n;
169 len -= n;
170
171 add_ubuf(current, ch);
172 }
173 flush_ubuf(current);
174 #else
175 DWORD nwritten;
176 COORD pos;
177
178 pos.Y = (SHORT)current->y;
179 pos.X = (SHORT)current->x;
180
181 SetConsoleCursorPosition(current->outh, pos);
182 WriteConsoleA(current->outh, pt, len, &nwritten, 0);
183
184 current->x += len;
185 #endif
186
187 sb_clear(current->output);
188
189 return 0;
190 }
191
192 static int outputChars(struct current *current, const char *buf, int len)
193 {
194 if (len < 0) {
195 len = strlen(buf);
196 }
197 assert(current->output);
198
199 sb_append_len(current->output, buf, len);
200
201 return 0;
202 }
203
204 static void outputNewline(struct current *current)
205 {
206 /* On the last row output a newline to force a scroll */
207 if (current->y + 1 == current->rows) {
208 outputChars(current, "\n", 1);
209 }
210 flushOutput(current);
211 current->x = 0;
212 current->y++;
213 }
214
215 static void setOutputHighlight(struct current *current, const int *props, int nprops)
216 {
217 int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
218 int bold = 0;
219 int reverse = 0;
220 int i;
221
222 for (i = 0; i < nprops; i++) {
223 switch (props[i]) {
224 case 0:
225 colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
226 bold = 0;
227 reverse = 0;
228 break;
229 case 1:
230 bold = FOREGROUND_INTENSITY;
231 break;
232 case 7:
233 reverse = 1;
234 break;
235 case 30:
236 colour = 0;
237 break;
238 case 31:
239 colour = FOREGROUND_RED;
240 break;
241 case 32:
242 colour = FOREGROUND_GREEN;
243 break;
244 case 33:
245 colour = FOREGROUND_RED | FOREGROUND_GREEN;
246 break;
247 case 34:
248 colour = FOREGROUND_BLUE;
249 break;
250 case 35:
251 colour = FOREGROUND_RED | FOREGROUND_BLUE;
252 break;
253 case 36:
254 colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
255 break;
256 case 37:
257 colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
258 break;
259 }
260 }
261
262 flushOutput(current);
263
264 if (reverse) {
265 SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
266 }
267 else {
268 SetConsoleTextAttribute(current->outh, colour | bold);
269 }
270 }
271
272 static void eraseEol(struct current *current)
273 {
274 COORD pos;
275 DWORD n;
276
277 pos.X = (SHORT) current->x;
278 pos.Y = (SHORT) current->y;
279
280 FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
281 }
282
283 static void setCursorXY(struct current *current)
284 {
285 COORD pos;
286
287 pos.X = (SHORT) current->x;
288 pos.Y = (SHORT) current->y;
289
290 SetConsoleCursorPosition(current->outh, pos);
291 }
292
293
294 static void setCursorPos(struct current *current, int x)
295 {
296 current->x = x;
297 setCursorXY(current);
298 }
299
300 static void cursorUp(struct current *current, int n)
301 {
302 current->y -= n;
303 setCursorXY(current);
304 }
305
306 static void cursorDown(struct current *current, int n)
307 {
308 current->y += n;
309 setCursorXY(current);
310 }
311
312 static int fd_read(struct current *current)
313 {
314 while (1) {
315 INPUT_RECORD irec;
316 DWORD n;
317 if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
318 break;
319 }
320 if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
321 break;
322 }
323 if (irec.EventType == KEY_EVENT) {
324 KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
325 if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
326 if (k->dwControlKeyState & ENHANCED_KEY) {
327 switch (k->wVirtualKeyCode) {
328 case VK_LEFT:
329 return SPECIAL_LEFT;
330 case VK_RIGHT:
331 return SPECIAL_RIGHT;
332 case VK_UP:
333 return SPECIAL_UP;
334 case VK_DOWN:
335 return SPECIAL_DOWN;
336 case VK_INSERT:
337 return SPECIAL_INSERT;
338 case VK_DELETE:
339 return SPECIAL_DELETE;
340 case VK_HOME:
341 return SPECIAL_HOME;
342 case VK_END:
343 return SPECIAL_END;
344 case VK_PRIOR:
345 return SPECIAL_PAGE_UP;
346 case VK_NEXT:
347 return SPECIAL_PAGE_DOWN;
348 case VK_RETURN:
349 return k->uChar.UnicodeChar;
350 }
351 }
352 /* Note that control characters are already translated in AsciiChar */
353 else if (k->wVirtualKeyCode == VK_CONTROL)
354 continue;
355 else {
356 return k->uChar.UnicodeChar;
357 }
358 }
359 }
360 }
361 return -1;
362 }
363
364 static int getWindowSize(struct current *current)
365 {
366 CONSOLE_SCREEN_BUFFER_INFO info;
367 if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
368 return -1;
369 }
370 current->cols = info.dwSize.X;
371 current->rows = info.dwSize.Y;
372 if (current->cols <= 0 || current->rows <= 0) {
373 current->cols = 80;
374 return -1;
375 }
376 current->y = info.dwCursorPosition.Y;
377 current->x = info.dwCursorPosition.X;
378 return 0;
379 }
+44 -18
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -892,10 +892,11 @@
892892
const char *prompt;
893893
stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
894894
stringbuf *output; /* used only during refreshLine() - output accumulator */
895895
#if defined(USE_TERMIOS)
896896
int fd; /* Terminal fd */
897
+ int pending; /* pending char fd_read_char() */
897898
#elif defined(USE_WINCONSOLE)
898899
HANDLE outh; /* Console output handle */
899900
HANDLE inh; /* Console input handle */
900901
int rows; /* Screen rows */
901902
int x; /* Current column during output */
@@ -1121,28 +1122,31 @@
11211122
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
11221123
/* control chars - set return condition: min number of bytes and timer.
11231124
* We want read to return every single byte, without timeout. */
11241125
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
11251126
1126
- /* put terminal in raw mode after flushing */
1127
- if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
1127
+ /* put terminal in raw mode. Because we aren't changing any output
1128
+ * settings we don't need to use TCSADRAIN and I have seen that hang on
1129
+ * OpenBSD when running under a pty
1130
+ */
1131
+ if (tcsetattr(current->fd,TCSANOW,&raw) < 0) {
11281132
goto fatal;
11291133
}
11301134
rawmode = 1;
11311135
return 0;
11321136
}
11331137
11341138
static void disableRawMode(struct current *current) {
11351139
/* Don't even check the return value as it's too late. */
1136
- if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
1140
+ if (rawmode && tcsetattr(current->fd,TCSANOW,&orig_termios) != -1)
11371141
rawmode = 0;
11381142
}
11391143
11401144
/* At exit we'll try to fix the terminal to the initial conditions. */
11411145
static void linenoiseAtExit(void) {
11421146
if (rawmode) {
1143
- tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
1147
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
11441148
}
11451149
linenoiseHistoryFree();
11461150
}
11471151
11481152
/* gcc/glibc insists that we care about the return code of write!
@@ -1230,29 +1234,35 @@
12301234
{
12311235
IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
12321236
}
12331237
12341238
/**
1235
- * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
1239
+ * Reads a char from 'current->fd', waiting at most 'timeout' milliseconds.
12361240
*
12371241
* A timeout of -1 means to wait forever.
12381242
*
12391243
* Returns -1 if no char is received within the time or an error occurs.
12401244
*/
1241
-static int fd_read_char(int fd, int timeout)
1245
+static int fd_read_char(struct current *current, int timeout)
12421246
{
12431247
struct pollfd p;
12441248
unsigned char c;
12451249
1246
- p.fd = fd;
1250
+ if (current->pending) {
1251
+ c = current->pending;
1252
+ current->pending = 0;
1253
+ return c;
1254
+ }
1255
+
1256
+ p.fd = current->fd;
12471257
p.events = POLLIN;
12481258
12491259
if (poll(&p, 1, timeout) == 0) {
12501260
/* timeout */
12511261
return -1;
12521262
}
1253
- if (read(fd, &c, 1) != 1) {
1263
+ if (read(current->fd, &c, 1) != 1) {
12541264
return -1;
12551265
}
12561266
return c;
12571267
}
12581268
@@ -1266,11 +1276,15 @@
12661276
char buf[MAX_UTF8_LEN];
12671277
int n;
12681278
int i;
12691279
int c;
12701280
1271
- if (read(current->fd, &buf[0], 1) != 1) {
1281
+ if (current->pending) {
1282
+ buf[0] = current->pending;
1283
+ current->pending = 0;
1284
+ }
1285
+ else if (read(current->fd, &buf[0], 1) != 1) {
12721286
return -1;
12731287
}
12741288
n = utf8_charlen(buf[0]);
12751289
if (n < 1) {
12761290
return -1;
@@ -1282,11 +1296,11 @@
12821296
}
12831297
/* decode and return the character */
12841298
utf8_tounicode(buf, &c);
12851299
return c;
12861300
#else
1287
- return fd_read_char(current->fd, -1);
1301
+ return fd_read_char(current, -1);
12881302
#endif
12891303
}
12901304
12911305
12921306
/**
@@ -1295,20 +1309,29 @@
12951309
*/
12961310
static int queryCursor(struct current *current, int* cols)
12971311
{
12981312
struct esc_parser parser;
12991313
int ch;
1314
+ /* Unfortunately we don't have any persistent state, so assume
1315
+ * a process will only ever interact with one terminal at a time.
1316
+ */
1317
+ static int query_cursor_failed;
1318
+
1319
+ if (query_cursor_failed) {
1320
+ /* If it ever fails, don't try again */
1321
+ return 0;
1322
+ }
13001323
13011324
/* Should not be buffering this output, it needs to go immediately */
13021325
assert(current->output == NULL);
13031326
13041327
/* control sequence - report cursor location */
13051328
outputChars(current, "\x1b[6n", -1);
13061329
13071330
/* Parse the response: ESC [ rows ; cols R */
13081331
initParseEscapeSeq(&parser, 'R');
1309
- while ((ch = fd_read_char(current->fd, 100)) > 0) {
1332
+ while ((ch = fd_read_char(current, 100)) > 0) {
13101333
switch (parseEscapeSequence(&parser, ch)) {
13111334
default:
13121335
continue;
13131336
case EP_END:
13141337
if (parser.numprops == 2 && parser.props[1] < 1000) {
@@ -1315,15 +1338,18 @@
13151338
*cols = parser.props[1];
13161339
return 1;
13171340
}
13181341
break;
13191342
case EP_ERROR:
1343
+ /* Push back the character that caused the error */
1344
+ current->pending = ch;
13201345
break;
13211346
}
13221347
/* failed */
13231348
break;
13241349
}
1350
+ query_cursor_failed = 1;
13251351
return 0;
13261352
}
13271353
13281354
/**
13291355
* Updates current->cols with the current window size (width)
@@ -1386,13 +1412,13 @@
13861412
* Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
13871413
*
13881414
* If no additional char is received within a short time,
13891415
* CHAR_ESCAPE is returned.
13901416
*/
1391
-static int check_special(int fd)
1417
+static int check_special(struct current *current)
13921418
{
1393
- int c = fd_read_char(fd, 50);
1419
+ int c = fd_read_char(current, 50);
13941420
int c2;
13951421
13961422
if (c < 0) {
13971423
return CHAR_ESCAPE;
13981424
}
@@ -1399,11 +1425,11 @@
13991425
else if (c >= 'a' && c <= 'z') {
14001426
/* esc-a => meta-a */
14011427
return meta(c);
14021428
}
14031429
1404
- c2 = fd_read_char(fd, 50);
1430
+ c2 = fd_read_char(current, 50);
14051431
if (c2 < 0) {
14061432
return c2;
14071433
}
14081434
if (c == '[' || c == 'O') {
14091435
/* Potential arrow key */
@@ -1422,11 +1448,11 @@
14221448
return SPECIAL_HOME;
14231449
}
14241450
}
14251451
if (c == '[' && c2 >= '1' && c2 <= '8') {
14261452
/* extended escape */
1427
- c = fd_read_char(fd, 50);
1453
+ c = fd_read_char(current, 50);
14281454
if (c == '~') {
14291455
switch (c2) {
14301456
case '2':
14311457
return SPECIAL_INSERT;
14321458
case '3':
@@ -1441,11 +1467,11 @@
14411467
return SPECIAL_END;
14421468
}
14431469
}
14441470
while (c != -1 && c != '~') {
14451471
/* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1446
- c = fd_read_char(fd, 50);
1472
+ c = fd_read_char(current, 50);
14471473
}
14481474
}
14491475
14501476
return SPECIAL_NONE;
14511477
}
@@ -2234,11 +2260,11 @@
22342260
}
22352261
continue;
22362262
}
22372263
#ifdef USE_TERMIOS
22382264
if (c == CHAR_ESCAPE) {
2239
- c = check_special(current->fd);
2265
+ c = check_special(current);
22402266
}
22412267
#endif
22422268
if (c == ctrl('R')) {
22432269
/* Search for the previous (earlier) match */
22442270
if (searchpos > 0) {
@@ -2346,11 +2372,11 @@
23462372
/* go on to process the returned char normally */
23472373
}
23482374
23492375
#ifdef USE_TERMIOS
23502376
if (c == CHAR_ESCAPE) { /* escape sequence */
2351
- c = check_special(current->fd);
2377
+ c = check_special(current);
23522378
}
23532379
#endif
23542380
if (c == -1) {
23552381
/* Return on errors */
23562382
return sb_len(current->buf);
23572383
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -892,10 +892,11 @@
892 const char *prompt;
893 stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
894 stringbuf *output; /* used only during refreshLine() - output accumulator */
895 #if defined(USE_TERMIOS)
896 int fd; /* Terminal fd */
 
897 #elif defined(USE_WINCONSOLE)
898 HANDLE outh; /* Console output handle */
899 HANDLE inh; /* Console input handle */
900 int rows; /* Screen rows */
901 int x; /* Current column during output */
@@ -1121,28 +1122,31 @@
1121 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
1122 /* control chars - set return condition: min number of bytes and timer.
1123 * We want read to return every single byte, without timeout. */
1124 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
1125
1126 /* put terminal in raw mode after flushing */
1127 if (tcsetattr(current->fd,TCSADRAIN,&raw) < 0) {
 
 
 
1128 goto fatal;
1129 }
1130 rawmode = 1;
1131 return 0;
1132 }
1133
1134 static void disableRawMode(struct current *current) {
1135 /* Don't even check the return value as it's too late. */
1136 if (rawmode && tcsetattr(current->fd,TCSADRAIN,&orig_termios) != -1)
1137 rawmode = 0;
1138 }
1139
1140 /* At exit we'll try to fix the terminal to the initial conditions. */
1141 static void linenoiseAtExit(void) {
1142 if (rawmode) {
1143 tcsetattr(STDIN_FILENO, TCSADRAIN, &orig_termios);
1144 }
1145 linenoiseHistoryFree();
1146 }
1147
1148 /* gcc/glibc insists that we care about the return code of write!
@@ -1230,29 +1234,35 @@
1230 {
1231 IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
1232 }
1233
1234 /**
1235 * Reads a char from 'fd', waiting at most 'timeout' milliseconds.
1236 *
1237 * A timeout of -1 means to wait forever.
1238 *
1239 * Returns -1 if no char is received within the time or an error occurs.
1240 */
1241 static int fd_read_char(int fd, int timeout)
1242 {
1243 struct pollfd p;
1244 unsigned char c;
1245
1246 p.fd = fd;
 
 
 
 
 
 
1247 p.events = POLLIN;
1248
1249 if (poll(&p, 1, timeout) == 0) {
1250 /* timeout */
1251 return -1;
1252 }
1253 if (read(fd, &c, 1) != 1) {
1254 return -1;
1255 }
1256 return c;
1257 }
1258
@@ -1266,11 +1276,15 @@
1266 char buf[MAX_UTF8_LEN];
1267 int n;
1268 int i;
1269 int c;
1270
1271 if (read(current->fd, &buf[0], 1) != 1) {
 
 
 
 
1272 return -1;
1273 }
1274 n = utf8_charlen(buf[0]);
1275 if (n < 1) {
1276 return -1;
@@ -1282,11 +1296,11 @@
1282 }
1283 /* decode and return the character */
1284 utf8_tounicode(buf, &c);
1285 return c;
1286 #else
1287 return fd_read_char(current->fd, -1);
1288 #endif
1289 }
1290
1291
1292 /**
@@ -1295,20 +1309,29 @@
1295 */
1296 static int queryCursor(struct current *current, int* cols)
1297 {
1298 struct esc_parser parser;
1299 int ch;
 
 
 
 
 
 
 
 
 
1300
1301 /* Should not be buffering this output, it needs to go immediately */
1302 assert(current->output == NULL);
1303
1304 /* control sequence - report cursor location */
1305 outputChars(current, "\x1b[6n", -1);
1306
1307 /* Parse the response: ESC [ rows ; cols R */
1308 initParseEscapeSeq(&parser, 'R');
1309 while ((ch = fd_read_char(current->fd, 100)) > 0) {
1310 switch (parseEscapeSequence(&parser, ch)) {
1311 default:
1312 continue;
1313 case EP_END:
1314 if (parser.numprops == 2 && parser.props[1] < 1000) {
@@ -1315,15 +1338,18 @@
1315 *cols = parser.props[1];
1316 return 1;
1317 }
1318 break;
1319 case EP_ERROR:
 
 
1320 break;
1321 }
1322 /* failed */
1323 break;
1324 }
 
1325 return 0;
1326 }
1327
1328 /**
1329 * Updates current->cols with the current window size (width)
@@ -1386,13 +1412,13 @@
1386 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
1387 *
1388 * If no additional char is received within a short time,
1389 * CHAR_ESCAPE is returned.
1390 */
1391 static int check_special(int fd)
1392 {
1393 int c = fd_read_char(fd, 50);
1394 int c2;
1395
1396 if (c < 0) {
1397 return CHAR_ESCAPE;
1398 }
@@ -1399,11 +1425,11 @@
1399 else if (c >= 'a' && c <= 'z') {
1400 /* esc-a => meta-a */
1401 return meta(c);
1402 }
1403
1404 c2 = fd_read_char(fd, 50);
1405 if (c2 < 0) {
1406 return c2;
1407 }
1408 if (c == '[' || c == 'O') {
1409 /* Potential arrow key */
@@ -1422,11 +1448,11 @@
1422 return SPECIAL_HOME;
1423 }
1424 }
1425 if (c == '[' && c2 >= '1' && c2 <= '8') {
1426 /* extended escape */
1427 c = fd_read_char(fd, 50);
1428 if (c == '~') {
1429 switch (c2) {
1430 case '2':
1431 return SPECIAL_INSERT;
1432 case '3':
@@ -1441,11 +1467,11 @@
1441 return SPECIAL_END;
1442 }
1443 }
1444 while (c != -1 && c != '~') {
1445 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1446 c = fd_read_char(fd, 50);
1447 }
1448 }
1449
1450 return SPECIAL_NONE;
1451 }
@@ -2234,11 +2260,11 @@
2234 }
2235 continue;
2236 }
2237 #ifdef USE_TERMIOS
2238 if (c == CHAR_ESCAPE) {
2239 c = check_special(current->fd);
2240 }
2241 #endif
2242 if (c == ctrl('R')) {
2243 /* Search for the previous (earlier) match */
2244 if (searchpos > 0) {
@@ -2346,11 +2372,11 @@
2346 /* go on to process the returned char normally */
2347 }
2348
2349 #ifdef USE_TERMIOS
2350 if (c == CHAR_ESCAPE) { /* escape sequence */
2351 c = check_special(current->fd);
2352 }
2353 #endif
2354 if (c == -1) {
2355 /* Return on errors */
2356 return sb_len(current->buf);
2357
--- extsrc/linenoise.c
+++ extsrc/linenoise.c
@@ -892,10 +892,11 @@
892 const char *prompt;
893 stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
894 stringbuf *output; /* used only during refreshLine() - output accumulator */
895 #if defined(USE_TERMIOS)
896 int fd; /* Terminal fd */
897 int pending; /* pending char fd_read_char() */
898 #elif defined(USE_WINCONSOLE)
899 HANDLE outh; /* Console output handle */
900 HANDLE inh; /* Console input handle */
901 int rows; /* Screen rows */
902 int x; /* Current column during output */
@@ -1121,28 +1122,31 @@
1122 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
1123 /* control chars - set return condition: min number of bytes and timer.
1124 * We want read to return every single byte, without timeout. */
1125 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
1126
1127 /* put terminal in raw mode. Because we aren't changing any output
1128 * settings we don't need to use TCSADRAIN and I have seen that hang on
1129 * OpenBSD when running under a pty
1130 */
1131 if (tcsetattr(current->fd,TCSANOW,&raw) < 0) {
1132 goto fatal;
1133 }
1134 rawmode = 1;
1135 return 0;
1136 }
1137
1138 static void disableRawMode(struct current *current) {
1139 /* Don't even check the return value as it's too late. */
1140 if (rawmode && tcsetattr(current->fd,TCSANOW,&orig_termios) != -1)
1141 rawmode = 0;
1142 }
1143
1144 /* At exit we'll try to fix the terminal to the initial conditions. */
1145 static void linenoiseAtExit(void) {
1146 if (rawmode) {
1147 tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
1148 }
1149 linenoiseHistoryFree();
1150 }
1151
1152 /* gcc/glibc insists that we care about the return code of write!
@@ -1230,29 +1234,35 @@
1234 {
1235 IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
1236 }
1237
1238 /**
1239 * Reads a char from 'current->fd', waiting at most 'timeout' milliseconds.
1240 *
1241 * A timeout of -1 means to wait forever.
1242 *
1243 * Returns -1 if no char is received within the time or an error occurs.
1244 */
1245 static int fd_read_char(struct current *current, int timeout)
1246 {
1247 struct pollfd p;
1248 unsigned char c;
1249
1250 if (current->pending) {
1251 c = current->pending;
1252 current->pending = 0;
1253 return c;
1254 }
1255
1256 p.fd = current->fd;
1257 p.events = POLLIN;
1258
1259 if (poll(&p, 1, timeout) == 0) {
1260 /* timeout */
1261 return -1;
1262 }
1263 if (read(current->fd, &c, 1) != 1) {
1264 return -1;
1265 }
1266 return c;
1267 }
1268
@@ -1266,11 +1276,15 @@
1276 char buf[MAX_UTF8_LEN];
1277 int n;
1278 int i;
1279 int c;
1280
1281 if (current->pending) {
1282 buf[0] = current->pending;
1283 current->pending = 0;
1284 }
1285 else if (read(current->fd, &buf[0], 1) != 1) {
1286 return -1;
1287 }
1288 n = utf8_charlen(buf[0]);
1289 if (n < 1) {
1290 return -1;
@@ -1282,11 +1296,11 @@
1296 }
1297 /* decode and return the character */
1298 utf8_tounicode(buf, &c);
1299 return c;
1300 #else
1301 return fd_read_char(current, -1);
1302 #endif
1303 }
1304
1305
1306 /**
@@ -1295,20 +1309,29 @@
1309 */
1310 static int queryCursor(struct current *current, int* cols)
1311 {
1312 struct esc_parser parser;
1313 int ch;
1314 /* Unfortunately we don't have any persistent state, so assume
1315 * a process will only ever interact with one terminal at a time.
1316 */
1317 static int query_cursor_failed;
1318
1319 if (query_cursor_failed) {
1320 /* If it ever fails, don't try again */
1321 return 0;
1322 }
1323
1324 /* Should not be buffering this output, it needs to go immediately */
1325 assert(current->output == NULL);
1326
1327 /* control sequence - report cursor location */
1328 outputChars(current, "\x1b[6n", -1);
1329
1330 /* Parse the response: ESC [ rows ; cols R */
1331 initParseEscapeSeq(&parser, 'R');
1332 while ((ch = fd_read_char(current, 100)) > 0) {
1333 switch (parseEscapeSequence(&parser, ch)) {
1334 default:
1335 continue;
1336 case EP_END:
1337 if (parser.numprops == 2 && parser.props[1] < 1000) {
@@ -1315,15 +1338,18 @@
1338 *cols = parser.props[1];
1339 return 1;
1340 }
1341 break;
1342 case EP_ERROR:
1343 /* Push back the character that caused the error */
1344 current->pending = ch;
1345 break;
1346 }
1347 /* failed */
1348 break;
1349 }
1350 query_cursor_failed = 1;
1351 return 0;
1352 }
1353
1354 /**
1355 * Updates current->cols with the current window size (width)
@@ -1386,13 +1412,13 @@
1412 * Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
1413 *
1414 * If no additional char is received within a short time,
1415 * CHAR_ESCAPE is returned.
1416 */
1417 static int check_special(struct current *current)
1418 {
1419 int c = fd_read_char(current, 50);
1420 int c2;
1421
1422 if (c < 0) {
1423 return CHAR_ESCAPE;
1424 }
@@ -1399,11 +1425,11 @@
1425 else if (c >= 'a' && c <= 'z') {
1426 /* esc-a => meta-a */
1427 return meta(c);
1428 }
1429
1430 c2 = fd_read_char(current, 50);
1431 if (c2 < 0) {
1432 return c2;
1433 }
1434 if (c == '[' || c == 'O') {
1435 /* Potential arrow key */
@@ -1422,11 +1448,11 @@
1448 return SPECIAL_HOME;
1449 }
1450 }
1451 if (c == '[' && c2 >= '1' && c2 <= '8') {
1452 /* extended escape */
1453 c = fd_read_char(current, 50);
1454 if (c == '~') {
1455 switch (c2) {
1456 case '2':
1457 return SPECIAL_INSERT;
1458 case '3':
@@ -1441,11 +1467,11 @@
1467 return SPECIAL_END;
1468 }
1469 }
1470 while (c != -1 && c != '~') {
1471 /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
1472 c = fd_read_char(current, 50);
1473 }
1474 }
1475
1476 return SPECIAL_NONE;
1477 }
@@ -2234,11 +2260,11 @@
2260 }
2261 continue;
2262 }
2263 #ifdef USE_TERMIOS
2264 if (c == CHAR_ESCAPE) {
2265 c = check_special(current);
2266 }
2267 #endif
2268 if (c == ctrl('R')) {
2269 /* Search for the previous (earlier) match */
2270 if (searchpos > 0) {
@@ -2346,11 +2372,11 @@
2372 /* go on to process the returned char normally */
2373 }
2374
2375 #ifdef USE_TERMIOS
2376 if (c == CHAR_ESCAPE) { /* escape sequence */
2377 c = check_special(current);
2378 }
2379 #endif
2380 if (c == -1) {
2381 /* Return on errors */
2382 return sb_len(current->buf);
2383
+349 -124
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -355,10 +355,15 @@
355355
**
356356
** The default behavior, if neither of the above is defined is to
357357
** use O_U8TEXT when writing to the Windows console (or anything
358358
** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
359359
** for all other output channels.
360
+**
361
+** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available. If
362
+** defined, it forces the use of Win32 APIs for all console I/O, both
363
+** input and output. This is necessary for some non-Microsoft run-times
364
+** that implement stdio differently from Microsoft/Visual-Studio.
360365
*/
361366
#if defined(SQLITE_U8TEXT_ONLY)
362367
# define UseWtextForOutput(fd) 1
363368
# define UseWtextForInput(fd) 1
364369
# define IsConsole(fd) _isatty(_fileno(fd))
@@ -457,14 +462,14 @@
457462
** that into UTF-8. Otherwise, non-ASCII characters all get translated
458463
** into '?'.
459464
*/
460465
wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
461466
if( b1==0 ) return 0;
462
-#ifndef SQLITE_USE_STDIO_FOR_CONSOLE
467
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
463468
DWORD nRead = 0;
464469
if( IsConsole(in)
465
- && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
470
+ && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0)
466471
){
467472
b1[nRead] = 0;
468473
}else
469474
#endif
470475
{
@@ -535,22 +540,23 @@
535540
wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
536541
if( b1==0 ) return 0;
537542
sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
538543
b1[sz] = 0;
539544
540
-#ifndef SQLITE_STDIO_FOR_CONSOLE
545
+#ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
541546
DWORD nWr = 0;
542547
if( IsConsole(out)
543548
&& WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
544549
){
545550
/* If writing to the console, then the WriteConsoleW() is all we
546551
** need to do. */
547552
}else
548553
#endif
549554
{
550
- /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
551
- ** then write using the standard library. */
555
+ /* As long as SQLITE_USE_W32_FOR_CONSOLE_IO is not defined, or for
556
+ ** non-console I/O even if that macro is defined, write using the
557
+ ** standard library. */
552558
_setmode(_fileno(out), _O_U8TEXT);
553559
if( UseBinaryWText(out) ){
554560
piecemealOutput(b1, sz, out);
555561
}else{
556562
fputws(b1, out);
@@ -843,11 +849,11 @@
843849
844850
/*
845851
** Prompt strings. Initialized in main. Settable with
846852
** .prompt main continue
847853
*/
848
-#define PROMPT_LEN_MAX 20
854
+#define PROMPT_LEN_MAX 128
849855
/* First line prompt. default: "sqlite> " */
850856
static char mainPrompt[PROMPT_LEN_MAX];
851857
/* Continuation prompt. default: " ...> " */
852858
static char continuePrompt[PROMPT_LEN_MAX];
853859
@@ -5289,31 +5295,34 @@
52895295
u8 bdp = BX_DV_PROTO(c);
52905296
switch( bdp ){
52915297
case ND:
52925298
/* Treat dark non-digits as pad, but they terminate decode too. */
52935299
ncIn = 0;
5294
- deliberate_fall_through;
5300
+ deliberate_fall_through; /* FALLTHRU */
52955301
case WS:
52965302
/* Treat whitespace as pad and terminate this group.*/
52975303
nti = nac;
5298
- deliberate_fall_through;
5304
+ deliberate_fall_through; /* FALLTHRU */
52995305
case PC:
53005306
bdp = 0;
53015307
--nbo;
5302
- deliberate_fall_through;
5308
+ deliberate_fall_through; /* FALLTHRU */
53035309
default: /* bdp is the digit value. */
53045310
qv = qv<<6 | bdp;
53055311
break;
53065312
}
53075313
}
53085314
switch( nbo ){
53095315
case 3:
53105316
pOut[2] = (qv) & 0xff;
5317
+ deliberate_fall_through; /* FALLTHRU */
53115318
case 2:
53125319
pOut[1] = (qv>>8) & 0xff;
5320
+ deliberate_fall_through; /* FALLTHRU */
53135321
case 1:
53145322
pOut[0] = (qv>>16) & 0xff;
5323
+ break;
53155324
}
53165325
pOut += nbo;
53175326
}
53185327
return pOut;
53195328
}
@@ -5644,16 +5653,20 @@
56445653
}
56455654
nbo -= nti; /* Adjust for early (non-digit) end of group. */
56465655
switch( nbo ){
56475656
case 4:
56485657
*pOut++ = (qv >> 24)&0xff;
5658
+ /* FALLTHRU */
56495659
case 3:
56505660
*pOut++ = (qv >> 16)&0xff;
5661
+ /* FALLTHRU */
56515662
case 2:
56525663
*pOut++ = (qv >> 8)&0xff;
5664
+ /* FALLTHRU */
56535665
case 1:
56545666
*pOut++ = qv&0xff;
5667
+ /* FALLTHRU */
56555668
case 0:
56565669
break;
56575670
}
56585671
}
56595672
return pOut;
@@ -7692,11 +7705,12 @@
76927705
76937706
/* Free and reclaim all the memory used by a previously compiled
76947707
** regular expression. Applications should invoke this routine once
76957708
** for every call to re_compile() to avoid memory leaks.
76967709
*/
7697
-static void re_free(ReCompiled *pRe){
7710
+static void re_free(void *p){
7711
+ ReCompiled *pRe = (ReCompiled*)p;
76987712
if( pRe ){
76997713
sqlite3_free(pRe->aOp);
77007714
sqlite3_free(pRe->aArg);
77017715
sqlite3_free(pRe);
77027716
}
@@ -8358,11 +8372,11 @@
83588372
LPWSTR zUnicodeName;
83598373
extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
83608374
83618375
GetSystemTime(&currentTime);
83628376
SystemTimeToFileTime(&currentTime, &lastAccess);
8363
- intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
8377
+ intervals = (mtime*10000000) + 116444736000000000;
83648378
lastWrite.dwLowDateTime = (DWORD)intervals;
83658379
lastWrite.dwHighDateTime = intervals >> 32;
83668380
zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
83678381
if( zUnicodeName==0 ){
83688382
return 1;
@@ -16344,10 +16358,11 @@
1634416358
#define VTR_DLCLOSE 0x00800000
1634516359
#define VTR_RAND 0x01000000
1634616360
#define VTR_SLEEP 0x02000000
1634716361
#define VTR_CURTIME 0x04000000
1634816362
#define VTR_LASTERR 0x08000000
16363
+#define VTR_FETCH 0x10000000 /* Also coverse xUnfetch */
1634916364
1635016365
/*
1635116366
** Method declarations for vfstrace_file.
1635216367
*/
1635316368
static int vfstraceClose(sqlite3_file*);
@@ -16773,10 +16788,11 @@
1677316788
{ "randomness", VTR_RAND },
1677416789
{ "sleep", VTR_SLEEP },
1677516790
{ "currenttime", VTR_CURTIME },
1677616791
{ "currenttimeint64", VTR_CURTIME },
1677716792
{ "getlasterror", VTR_LASTERR },
16793
+ { "fetch", VTR_FETCH },
1677816794
};
1677916795
int onOff = 1;
1678016796
while( zArg[0] ){
1678116797
int jj, n;
1678216798
while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
@@ -17000,11 +17016,32 @@
1700017016
pInfo->zVfsName, p->zFName, delFlag);
1700117017
rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
1700217018
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
1700317019
return rc;
1700417020
}
17005
-
17021
+static int vfstraceFetch(sqlite3_file *pFile, i64 iOff, int nAmt, void **pptr){
17022
+ vfstrace_file *p = (vfstrace_file *)pFile;
17023
+ vfstrace_info *pInfo = p->pInfo;
17024
+ int rc;
17025
+ vfstraceOnOff(pInfo, VTR_FETCH);
17026
+ vfstrace_printf(pInfo, "%s.xFetch(%s,iOff=%lld,nAmt=%d,p=%p)",
17027
+ pInfo->zVfsName, p->zFName, iOff, nAmt, *pptr);
17028
+ rc = p->pReal->pMethods->xFetch(p->pReal, iOff, nAmt, pptr);
17029
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17030
+ return rc;
17031
+}
17032
+static int vfstraceUnfetch(sqlite3_file *pFile, i64 iOff, void *ptr){
17033
+ vfstrace_file *p = (vfstrace_file *)pFile;
17034
+ vfstrace_info *pInfo = p->pInfo;
17035
+ int rc;
17036
+ vfstraceOnOff(pInfo, VTR_FETCH);
17037
+ vfstrace_printf(pInfo, "%s.xUnfetch(%s,iOff=%lld,p=%p)",
17038
+ pInfo->zVfsName, p->zFName, iOff, ptr);
17039
+ rc = p->pReal->pMethods->xUnfetch(p->pReal, iOff, ptr);
17040
+ vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17041
+ return rc;
17042
+}
1700617043
1700717044
1700817045
/*
1700917046
** Open an vfstrace file handle.
1701017047
*/
@@ -17047,10 +17084,14 @@
1704717084
pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
1704817085
pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
1704917086
pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
1705017087
pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
1705117088
}
17089
+ if( pNew->iVersion>=3 ){
17090
+ pNew->xFetch = pSub->xFetch ? vfstraceFetch : 0;
17091
+ pNew->xUnfetch = pSub->xUnfetch ? vfstraceUnfetch : 0;
17092
+ }
1705217093
pFile->pMethods = pNew;
1705317094
}
1705417095
vfstrace_print_errcode(pInfo, " -> %s", rc);
1705517096
if( pOutFlags ){
1705617097
vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
@@ -17162,11 +17203,11 @@
1716217203
*/
1716317204
static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
1716417205
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
1716517206
sqlite3_vfs *pRoot = pInfo->pRootVfs;
1716617207
vfstraceOnOff(pInfo, VTR_DLCLOSE);
17167
- vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
17208
+ vfstrace_printf(pInfo, "%s.xDlClose()\n", pInfo->zVfsName);
1716817209
pRoot->xDlClose(pRoot, pHandle);
1716917210
}
1717017211
1717117212
/*
1717217213
** Populate the buffer pointed to by zBufOut with nByte bytes of
@@ -21569,10 +21610,11 @@
2156921610
u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
2157021611
u8 bSafeMode; /* True to prohibit unsafe operations */
2157121612
u8 bSafeModePersist; /* The long-term value of bSafeMode */
2157221613
u8 eRestoreState; /* See comments above doAutoDetectRestore() */
2157321614
u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
21615
+ u8 eEscMode; /* Escape mode for text output */
2157421616
ColModeOpts cmOpts; /* Option values affecting columnar mode output */
2157521617
unsigned statsOn; /* True to display memory stats before each finalize */
2157621618
unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
2157721619
int inputNesting; /* Track nesting level of .read and other redirects */
2157821620
int outCount; /* Revert to stdout when reaching zero */
@@ -21669,10 +21711,18 @@
2166921711
#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
2167021712
** callback limit is reached, and for each
2167121713
** top-level SQL statement */
2167221714
#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
2167321715
21716
+/* Allowed values for ShellState.eEscMode
21717
+*/
21718
+#define SHELL_ESC_SYMBOL 0 /* Substitute U+2400 graphics */
21719
+#define SHELL_ESC_ASCII 1 /* Substitute ^Y for X where Y=X+0x40 */
21720
+#define SHELL_ESC_OFF 2 /* Send characters verbatim */
21721
+
21722
+static const char *shell_EscModeNames[] = { "symbol", "ascii", "off" };
21723
+
2167421724
/*
2167521725
** These are the allowed shellFlgs values
2167621726
*/
2167721727
#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
2167821728
#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
@@ -22006,63 +22056,79 @@
2200622056
sqlite3_fprintf(out, "X'%s'", zStr);
2200722057
sqlite3_free(zStr);
2200822058
}
2200922059
2201022060
/*
22011
-** Find a string that is not found anywhere in z[]. Return a pointer
22012
-** to that string.
22013
-**
22014
-** Try to use zA and zB first. If both of those are already found in z[]
22015
-** then make up some string and store it in the buffer zBuf.
22016
-*/
22017
-static const char *unused_string(
22018
- const char *z, /* Result must not appear anywhere in z */
22019
- const char *zA, const char *zB, /* Try these first */
22020
- char *zBuf /* Space to store a generated string */
22021
-){
22022
- unsigned i = 0;
22023
- if( strstr(z, zA)==0 ) return zA;
22024
- if( strstr(z, zB)==0 ) return zB;
22025
- do{
22026
- sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
22027
- }while( strstr(z,zBuf)!=0 );
22028
- return zBuf;
22029
-}
22030
-
22031
-/*
22032
-** Output the given string as a quoted string using SQL quoting conventions.
22033
-**
22034
-** See also: output_quoted_escaped_string()
22035
-*/
22036
-static void output_quoted_string(ShellState *p, const char *z){
22037
- int i;
22038
- char c;
22061
+** Output the given string as a quoted string using SQL quoting conventions:
22062
+**
22063
+** (1) Single quotes (') within the string are doubled
22064
+** (2) The whle string is enclosed in '...'
22065
+** (3) Control characters other than \n, \t, and \r\n are escaped
22066
+** using \u00XX notation and if such substitutions occur,
22067
+** the whole string is enclosed in unistr('...') instead of '...'.
22068
+**
22069
+** Step (3) is omitted if the control-character escape mode is OFF.
22070
+**
22071
+** See also: output_quoted_escaped_string() which does the same except
22072
+** that it does not make exceptions for \n, \t, and \r\n in step (3).
22073
+*/
22074
+static void output_quoted_string(ShellState *p, const char *zInX){
22075
+ int i;
22076
+ int needUnistr = 0;
22077
+ int needDblQuote = 0;
22078
+ const unsigned char *z = (const unsigned char*)zInX;
22079
+ unsigned char c;
2203922080
FILE *out = p->out;
2204022081
sqlite3_fsetmode(out, _O_BINARY);
2204122082
if( z==0 ) return;
22042
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22043
- if( c==0 ){
22083
+ for(i=0; (c = z[i])!=0; i++){
22084
+ if( c=='\'' ){ needDblQuote = 1; }
22085
+ if( c>0x1f ) continue;
22086
+ if( c=='\t' || c=='\n' ) continue;
22087
+ if( c=='\r' && z[i+1]=='\n' ) continue;
22088
+ needUnistr = 1;
22089
+ break;
22090
+ }
22091
+ if( (needDblQuote==0 && needUnistr==0)
22092
+ || (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF)
22093
+ ){
2204422094
sqlite3_fprintf(out, "'%s'",z);
22095
+ }else if( p->eEscMode==SHELL_ESC_OFF ){
22096
+ char *zEncoded = sqlite3_mprintf("%Q", z);
22097
+ sqlite3_fputs(zEncoded, out);
22098
+ sqlite3_free(zEncoded);
2204522099
}else{
22046
- sqlite3_fputs("'", out);
22100
+ if( needUnistr ){
22101
+ sqlite3_fputs("unistr('", out);
22102
+ }else{
22103
+ sqlite3_fputs("'", out);
22104
+ }
2204722105
while( *z ){
22048
- for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22049
- if( c=='\'' ) i++;
22106
+ for(i=0; (c = z[i])!=0; i++){
22107
+ if( c=='\'' ) break;
22108
+ if( c>0x1f ) continue;
22109
+ if( c=='\t' || c=='\n' ) continue;
22110
+ if( c=='\r' && z[i+1]=='\n' ) continue;
22111
+ break;
22112
+ }
2205022113
if( i ){
2205122114
sqlite3_fprintf(out, "%.*s", i, z);
2205222115
z += i;
2205322116
}
22117
+ if( c==0 ) break;
2205422118
if( c=='\'' ){
22055
- sqlite3_fputs("'", out);
22056
- continue;
22057
- }
22058
- if( c==0 ){
22059
- break;
22119
+ sqlite3_fputs("''", out);
22120
+ }else{
22121
+ sqlite3_fprintf(out, "\\u%04x", c);
2206022122
}
2206122123
z++;
2206222124
}
22063
- sqlite3_fputs("'", out);
22125
+ if( needUnistr ){
22126
+ sqlite3_fputs("')", out);
22127
+ }else{
22128
+ sqlite3_fputs("'", out);
22129
+ }
2206422130
}
2206522131
setCrlfMode(p);
2206622132
}
2206722133
2206822134
/*
@@ -22073,65 +22139,19 @@
2207322139
**
2207422140
** This is like output_quoted_string() but with the addition of the \r\n
2207522141
** escape mechanism.
2207622142
*/
2207722143
static void output_quoted_escaped_string(ShellState *p, const char *z){
22078
- int i;
22079
- char c;
22080
- FILE *out = p->out;
22081
- sqlite3_fsetmode(out, _O_BINARY);
22082
- for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
22083
- if( c==0 ){
22084
- sqlite3_fprintf(out, "'%s'",z);
22144
+ char *zEscaped;
22145
+ sqlite3_fsetmode(p->out, _O_BINARY);
22146
+ if( p->eEscMode==SHELL_ESC_OFF ){
22147
+ zEscaped = sqlite3_mprintf("%Q", z);
2208522148
}else{
22086
- const char *zNL = 0;
22087
- const char *zCR = 0;
22088
- int nNL = 0;
22089
- int nCR = 0;
22090
- char zBuf1[20], zBuf2[20];
22091
- for(i=0; z[i]; i++){
22092
- if( z[i]=='\n' ) nNL++;
22093
- if( z[i]=='\r' ) nCR++;
22094
- }
22095
- if( nNL ){
22096
- sqlite3_fputs("replace(", out);
22097
- zNL = unused_string(z, "\\n", "\\012", zBuf1);
22098
- }
22099
- if( nCR ){
22100
- sqlite3_fputs("replace(", out);
22101
- zCR = unused_string(z, "\\r", "\\015", zBuf2);
22102
- }
22103
- sqlite3_fputs("'", out);
22104
- while( *z ){
22105
- for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
22106
- if( c=='\'' ) i++;
22107
- if( i ){
22108
- sqlite3_fprintf(out, "%.*s", i, z);
22109
- z += i;
22110
- }
22111
- if( c=='\'' ){
22112
- sqlite3_fputs("'", out);
22113
- continue;
22114
- }
22115
- if( c==0 ){
22116
- break;
22117
- }
22118
- z++;
22119
- if( c=='\n' ){
22120
- sqlite3_fputs(zNL, out);
22121
- continue;
22122
- }
22123
- sqlite3_fputs(zCR, out);
22124
- }
22125
- sqlite3_fputs("'", out);
22126
- if( nCR ){
22127
- sqlite3_fprintf(out, ",'%s',char(13))", zCR);
22128
- }
22129
- if( nNL ){
22130
- sqlite3_fprintf(out, ",'%s',char(10))", zNL);
22131
- }
22132
- }
22149
+ zEscaped = sqlite3_mprintf("%#Q", z);
22150
+ }
22151
+ sqlite3_fputs(zEscaped, p->out);
22152
+ sqlite3_free(zEscaped);
2213322153
setCrlfMode(p);
2213422154
}
2213522155
2213622156
/*
2213722157
** Find earliest of chars within s specified in zAny.
@@ -22276,10 +22296,97 @@
2227622296
sqlite3_fputs(ace+1, out);
2227722297
}
2227822298
}
2227922299
sqlite3_fputs(zq, out);
2228022300
}
22301
+
22302
+/*
22303
+** Escape the input string if it is needed and in accordance with
22304
+** eEscMode.
22305
+**
22306
+** Escaping is needed if the string contains any control characters
22307
+** other than \t, \n, and \r\n
22308
+**
22309
+** If no escaping is needed (the common case) then set *ppFree to NULL
22310
+** and return the original string. If escapingn is needed, write the
22311
+** escaped string into memory obtained from sqlite3_malloc64() or the
22312
+** equivalent, and return the new string and set *ppFree to the new string
22313
+** as well.
22314
+**
22315
+** The caller is responsible for freeing *ppFree if it is non-NULL in order
22316
+** to reclaim memory.
22317
+*/
22318
+static const char *escapeOutput(
22319
+ ShellState *p,
22320
+ const char *zInX,
22321
+ char **ppFree
22322
+){
22323
+ i64 i, j;
22324
+ i64 nCtrl = 0;
22325
+ unsigned char *zIn;
22326
+ unsigned char c;
22327
+ unsigned char *zOut;
22328
+
22329
+
22330
+ /* No escaping if disabled */
22331
+ if( p->eEscMode==SHELL_ESC_OFF ){
22332
+ *ppFree = 0;
22333
+ return zInX;
22334
+ }
22335
+
22336
+ /* Count the number of control characters in the string. */
22337
+ zIn = (unsigned char*)zInX;
22338
+ for(i=0; (c = zIn[i])!=0; i++){
22339
+ if( c<=0x1f
22340
+ && c!='\t'
22341
+ && c!='\n'
22342
+ && (c!='\r' || zIn[i+1]!='\n')
22343
+ ){
22344
+ nCtrl++;
22345
+ }
22346
+ }
22347
+ if( nCtrl==0 ){
22348
+ *ppFree = 0;
22349
+ return zInX;
22350
+ }
22351
+ if( p->eEscMode==SHELL_ESC_SYMBOL ) nCtrl *= 2;
22352
+ zOut = sqlite3_malloc64( i + nCtrl + 1 );
22353
+ shell_check_oom(zOut);
22354
+ for(i=j=0; (c = zIn[i])!=0; i++){
22355
+ if( c>0x1f
22356
+ || c=='\t'
22357
+ || c=='\n'
22358
+ || (c=='\r' && zIn[i+1]=='\n')
22359
+ ){
22360
+ continue;
22361
+ }
22362
+ if( i>0 ){
22363
+ memcpy(&zOut[j], zIn, i);
22364
+ j += i;
22365
+ }
22366
+ zIn += i+1;
22367
+ i = -1;
22368
+ switch( p->eEscMode ){
22369
+ case SHELL_ESC_SYMBOL:
22370
+ zOut[j++] = 0xe2;
22371
+ zOut[j++] = 0x90;
22372
+ zOut[j++] = 0x80+c;
22373
+ break;
22374
+ case SHELL_ESC_ASCII:
22375
+ zOut[j++] = '^';
22376
+ zOut[j++] = 0x40+c;
22377
+ break;
22378
+ }
22379
+ }
22380
+ if( i>0 ){
22381
+ memcpy(&zOut[j], zIn, i);
22382
+ j += i;
22383
+ }
22384
+ zOut[j] = 0;
22385
+ *ppFree = (char*)zOut;
22386
+ return (char*)zOut;
22387
+}
2228122388
2228222389
/*
2228322390
** Output the given string with characters that are special to
2228422391
** HTML escaped.
2228522392
*/
@@ -22720,12 +22827,16 @@
2272022827
int len = strlen30(azCol[i] ? azCol[i] : "");
2272122828
if( len>w ) w = len;
2272222829
}
2272322830
if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
2272422831
for(i=0; i<nArg; i++){
22832
+ char *pFree = 0;
22833
+ const char *pDisplay;
22834
+ pDisplay = escapeOutput(p, azArg[i] ? azArg[i] : p->nullValue, &pFree);
2272522835
sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
22726
- azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
22836
+ pDisplay, p->rowSeparator);
22837
+ if( pFree ) sqlite3_free(pFree);
2272722838
}
2272822839
break;
2272922840
}
2273022841
case MODE_ScanExp:
2273122842
case MODE_Explain: {
@@ -22853,19 +22964,27 @@
2285322964
break;
2285422965
}
2285522966
case MODE_List: {
2285622967
if( p->cnt++==0 && p->showHeader ){
2285722968
for(i=0; i<nArg; i++){
22858
- sqlite3_fprintf(p->out, "%s%s", azCol[i],
22969
+ char *z = azCol[i];
22970
+ char *pFree;
22971
+ const char *zOut = escapeOutput(p, z, &pFree);
22972
+ sqlite3_fprintf(p->out, "%s%s", zOut,
2285922973
i==nArg-1 ? p->rowSeparator : p->colSeparator);
22974
+ if( pFree ) sqlite3_free(pFree);
2286022975
}
2286122976
}
2286222977
if( azArg==0 ) break;
2286322978
for(i=0; i<nArg; i++){
2286422979
char *z = azArg[i];
22980
+ char *pFree;
22981
+ const char *zOut;
2286522982
if( z==0 ) z = p->nullValue;
22866
- sqlite3_fputs(z, p->out);
22983
+ zOut = escapeOutput(p, z, &pFree);
22984
+ sqlite3_fputs(zOut, p->out);
22985
+ if( pFree ) sqlite3_free(pFree);
2286722986
sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
2286822987
}
2286922988
break;
2287022989
}
2287122990
case MODE_Www:
@@ -23980,10 +24099,11 @@
2398024099
** from malloc()) of that first line, which caller should free sometime.
2398124100
** Write anything to display on the next line into *pzTail. If this is
2398224101
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
2398324102
*/
2398424103
static char *translateForDisplayAndDup(
24104
+ ShellState *p, /* To access current settings */
2398524105
const unsigned char *z, /* Input text to be transformed */
2398624106
const unsigned char **pzTail, /* OUT: Tail of the input for next line */
2398724107
int mxWidth, /* Max width. 0 means no limit */
2398824108
u8 bWordWrap /* If true, avoid breaking mid-word */
2398924109
){
@@ -24014,19 +24134,22 @@
2401424134
n++;
2401524135
i++;
2401624136
j++;
2401724137
continue;
2401824138
}
24139
+ if( c==0 || c=='\n' || (c=='\r' && z[i+1]=='\n') ) break;
2401924140
if( c=='\t' ){
2402024141
do{
2402124142
n++;
2402224143
j++;
2402324144
}while( (n&7)!=0 && n<mxWidth );
2402424145
i++;
2402524146
continue;
2402624147
}
24027
- break;
24148
+ n++;
24149
+ j += 3;
24150
+ i++;
2402824151
}
2402924152
if( n>=mxWidth && bWordWrap ){
2403024153
/* Perhaps try to back up to a better place to break the line */
2403124154
for(k=i; k>i/2; k--){
2403224155
if( isspace(z[k-1]) ) break;
@@ -24069,23 +24192,48 @@
2406924192
if( c>=' ' ){
2407024193
n++;
2407124194
zOut[j++] = z[i++];
2407224195
continue;
2407324196
}
24197
+ if( c==0 ) break;
2407424198
if( z[i]=='\t' ){
2407524199
do{
2407624200
n++;
2407724201
zOut[j++] = ' ';
2407824202
}while( (n&7)!=0 && n<mxWidth );
2407924203
i++;
2408024204
continue;
2408124205
}
24082
- break;
24206
+ switch( p->eEscMode ){
24207
+ case SHELL_ESC_SYMBOL:
24208
+ zOut[j++] = 0xe2;
24209
+ zOut[j++] = 0x90;
24210
+ zOut[j++] = 0x80 + c;
24211
+ break;
24212
+ case SHELL_ESC_ASCII:
24213
+ zOut[j++] = '^';
24214
+ zOut[j++] = 0x40 + c;
24215
+ break;
24216
+ case SHELL_ESC_OFF:
24217
+ zOut[j++] = c;
24218
+ break;
24219
+ }
24220
+ i++;
2408324221
}
2408424222
zOut[j] = 0;
2408524223
return (char*)zOut;
2408624224
}
24225
+
24226
+/* Return true if the text string z[] contains characters that need
24227
+** unistr() escaping.
24228
+*/
24229
+static int needUnistr(const unsigned char *z){
24230
+ unsigned char c;
24231
+ if( z==0 ) return 0;
24232
+ while( (c = *z)>0x1f || c=='\t' || c=='\n' || (c=='\r' && z[1]=='\n') ){ z++; }
24233
+ return c!=0;
24234
+}
2408724235
2408824236
/* Extract the value of the i-th current column for pStmt as an SQL literal
2408924237
** value. Memory is obtained from sqlite3_malloc64() and must be freed by
2409024238
** the caller.
2409124239
*/
@@ -24097,11 +24245,12 @@
2409724245
case SQLITE_INTEGER:
2409824246
case SQLITE_FLOAT: {
2409924247
return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
2410024248
}
2410124249
case SQLITE_TEXT: {
24102
- return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
24250
+ const unsigned char *zText = sqlite3_column_text(pStmt,i);
24251
+ return sqlite3_mprintf(needUnistr(zText)?"%#Q":"%Q",zText);
2410324252
}
2410424253
case SQLITE_BLOB: {
2410524254
int j;
2410624255
sqlite3_str *pStr = sqlite3_str_new(0);
2410724256
const unsigned char *a = sqlite3_column_blob(pStmt,i);
@@ -24189,11 +24338,11 @@
2418924338
wx = p->cmOpts.iWrap;
2419024339
}
2419124340
if( wx<0 ) wx = -wx;
2419224341
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
2419324342
if( uz==0 ) uz = (u8*)"";
24194
- azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
24343
+ azData[i] = translateForDisplayAndDup(p, uz, &zNotUsed, wx, bw);
2419524344
}
2419624345
do{
2419724346
int useNextLine = bNextLine;
2419824347
bNextLine = 0;
2419924348
if( (nRow+2)*nColumn >= nAlloc ){
@@ -24213,19 +24362,20 @@
2421324362
if( wx<0 ) wx = -wx;
2421424363
if( useNextLine ){
2421524364
uz = azNextLine[i];
2421624365
if( uz==0 ) uz = (u8*)zEmpty;
2421724366
}else if( p->cmOpts.bQuote ){
24367
+ assert( azQuoted!=0 );
2421824368
sqlite3_free(azQuoted[i]);
2421924369
azQuoted[i] = quoted_column(pStmt,i);
2422024370
uz = (const unsigned char*)azQuoted[i];
2422124371
}else{
2422224372
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
2422324373
if( uz==0 ) uz = (u8*)zShowNull;
2422424374
}
2422524375
azData[nRow*nColumn + i]
24226
- = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
24376
+ = translateForDisplayAndDup(p, uz, &azNextLine[i], wx, bw);
2422724377
if( azNextLine[i] ){
2422824378
bNextLine = 1;
2422924379
abRowDiv[nRow-1] = 0;
2423024380
bMultiLineRowExists = 1;
2423124381
}
@@ -25144,11 +25294,11 @@
2514425294
#if !defined(SQLITE_SHELL_FIDDLE)
2514525295
".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout",
2514625296
#else
2514725297
".log on|off Turn logging on or off.",
2514825298
#endif
25149
- ".mode MODE ?OPTIONS? Set output mode",
25299
+ ".mode ?MODE? ?OPTIONS? Set output mode",
2515025300
" MODE is one of:",
2515125301
" ascii Columns/rows delimited by 0x1F and 0x1E",
2515225302
" box Tables using unicode box-drawing characters",
2515325303
" csv Comma-separated values",
2515425304
" column Output in columns. (See .width)",
@@ -25162,10 +25312,11 @@
2516225312
" quote Escape answers as for SQL",
2516325313
" table ASCII-art table",
2516425314
" tabs Tab-separated values",
2516525315
" tcl TCL list elements",
2516625316
" OPTIONS: (for columnar modes or insert mode):",
25317
+ " --escape T ctrl-char escape; T is one of: symbol, ascii, off",
2516725318
" --wrap N Wrap output lines to no longer than N characters",
2516825319
" --wordwrap B Wrap or not at word boundaries per B (on/off)",
2516925320
" --ww Shorthand for \"--wordwrap 1\"",
2517025321
" --quote Quote output text as SQL literals",
2517125322
" --noquote Do not quote output text",
@@ -27460,11 +27611,11 @@
2746027611
case AR_SWITCH_VERBOSE:
2746127612
pAr->bVerbose = 1;
2746227613
break;
2746327614
case AR_SWITCH_APPEND:
2746427615
pAr->bAppend = 1;
27465
- deliberate_fall_through;
27616
+ deliberate_fall_through; /* FALLTHRU */
2746627617
case AR_SWITCH_FILE:
2746727618
pAr->zFile = zArg;
2746827619
break;
2746927620
case AR_SWITCH_DIRECTORY:
2747027621
pAr->zDir = zArg;
@@ -28848,10 +28999,13 @@
2884828999
if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
2884929000
static const struct DbConfigChoices {
2885029001
const char *zName;
2885129002
int op;
2885229003
} aDbConfig[] = {
29004
+ { "attach_create", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
29005
+ { "attach_write", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
29006
+ { "comments", SQLITE_DBCONFIG_ENABLE_COMMENTS },
2885329007
{ "defensive", SQLITE_DBCONFIG_DEFENSIVE },
2885429008
{ "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
2885529009
{ "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
2885629010
{ "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
2885729011
{ "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
@@ -29899,28 +30053,56 @@
2989930053
2990030054
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
2990130055
const char *zMode = 0;
2990230056
const char *zTabname = 0;
2990330057
int i, n2;
30058
+ int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */
2990430059
ColModeOpts cmOpts = ColModeOpts_default;
2990530060
for(i=1; i<nArg; i++){
2990630061
const char *z = azArg[i];
2990730062
if( optionMatch(z,"wrap") && i+1<nArg ){
2990830063
cmOpts.iWrap = integerValue(azArg[++i]);
30064
+ chng |= 1;
2990930065
}else if( optionMatch(z,"ww") ){
2991030066
cmOpts.bWordWrap = 1;
30067
+ chng |= 1;
2991130068
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
2991230069
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
30070
+ chng |= 1;
2991330071
}else if( optionMatch(z,"quote") ){
2991430072
cmOpts.bQuote = 1;
30073
+ chng |= 1;
2991530074
}else if( optionMatch(z,"noquote") ){
2991630075
cmOpts.bQuote = 0;
30076
+ chng |= 1;
30077
+ }else if( optionMatch(z,"escape") && i+1<nArg ){
30078
+ /* See similar code at tag-20250224-1 */
30079
+ const char *zEsc = azArg[++i];
30080
+ int k;
30081
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
30082
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
30083
+ p->eEscMode = k;
30084
+ chng |= 2;
30085
+ break;
30086
+ }
30087
+ }
30088
+ if( k>=ArraySize(shell_EscModeNames) ){
30089
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
30090
+ " - choices:", zEsc);
30091
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
30092
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
30093
+ }
30094
+ sqlite3_fprintf(stderr, "\n");
30095
+ rc = 1;
30096
+ goto meta_command_exit;
30097
+ }
2991730098
}else if( zMode==0 ){
2991830099
zMode = z;
2991930100
/* Apply defaults for qbox pseudo-mode. If that
2992030101
* overwrites already-set values, user was informed of this.
2992130102
*/
30103
+ chng |= 1;
2992230104
if( cli_strcmp(z, "qbox")==0 ){
2992330105
ColModeOpts cmo = ColModeOpts_default_qbox;
2992430106
zMode = "box";
2992530107
cmOpts = cmo;
2992630108
}
@@ -29927,10 +30109,11 @@
2992730109
}else if( zTabname==0 ){
2992830110
zTabname = z;
2992930111
}else if( z[0]=='-' ){
2993030112
sqlite3_fprintf(stderr,"unknown option: %s\n", z);
2993130113
eputz("options:\n"
30114
+ " --escape MODE\n"
2993230115
" --noquote\n"
2993330116
" --quote\n"
2993430117
" --wordwrap on/off\n"
2993530118
" --wrap N\n"
2993630119
" --ww\n");
@@ -29940,24 +30123,33 @@
2994030123
sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
2994130124
rc = 1;
2994230125
goto meta_command_exit;
2994330126
}
2994430127
}
29945
- if( zMode==0 ){
30128
+ if( !chng ){
2994630129
if( p->mode==MODE_Column
2994730130
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
2994830131
){
2994930132
sqlite3_fprintf(p->out,
29950
- "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
30133
+ "current output mode: %s --wrap %d --wordwrap %s "
30134
+ "--%squote --escape %s\n",
2995130135
modeDescr[p->mode], p->cmOpts.iWrap,
2995230136
p->cmOpts.bWordWrap ? "on" : "off",
29953
- p->cmOpts.bQuote ? "" : "no");
30137
+ p->cmOpts.bQuote ? "" : "no",
30138
+ shell_EscModeNames[p->eEscMode]
30139
+ );
2995430140
}else{
2995530141
sqlite3_fprintf(p->out,
29956
- "current output mode: %s\n", modeDescr[p->mode]);
30142
+ "current output mode: %s --escape %s\n",
30143
+ modeDescr[p->mode],
30144
+ shell_EscModeNames[p->eEscMode]
30145
+ );
2995730146
}
30147
+ }
30148
+ if( zMode==0 ){
2995830149
zMode = modeDescr[p->mode];
30150
+ if( (chng&1)==0 ) cmOpts = p->cmOpts;
2995930151
}
2996030152
n2 = strlen30(zMode);
2996130153
if( cli_strncmp(zMode,"lines",n2)==0 ){
2996230154
p->mode = MODE_Line;
2996330155
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
@@ -29986,10 +30178,15 @@
2998630178
p->mode = MODE_List;
2998730179
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
2998830180
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
2998930181
p->mode = MODE_Insert;
2999030182
set_table_name(p, zTabname ? zTabname : "table");
30183
+ if( p->eEscMode==SHELL_ESC_OFF ){
30184
+ ShellSetFlag(p, SHFLG_Newlines);
30185
+ }else{
30186
+ ShellClearFlag(p, SHFLG_Newlines);
30187
+ }
2999130188
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
2999230189
p->mode = MODE_Quote;
2999330190
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
2999430191
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
2999530192
}else if( cli_strncmp(zMode,"ascii",n2)==0 ){
@@ -30202,10 +30399,11 @@
3020230399
}
3020330400
}
3020430401
if( zFile==0 ){
3020530402
zFile = sqlite3_mprintf("stdout");
3020630403
}
30404
+ shell_check_oom(zFile);
3020730405
if( bOnce ){
3020830406
p->outCount = 2;
3020930407
}else{
3021030408
p->outCount = 0;
3021130409
}
@@ -30244,10 +30442,11 @@
3024430442
rc = 1;
3024530443
output_redir(p, stdout);
3024630444
#else
3024730445
FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
3024830446
if( pfPipe==0 ){
30447
+ assert( stderr!=NULL );
3024930448
sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
3025030449
rc = 1;
3025130450
}else{
3025230451
output_redir(p, pfPipe);
3025330452
if( zBom ) sqlite3_fputs(zBom, pfPipe);
@@ -30256,11 +30455,12 @@
3025630455
#endif
3025730456
}else{
3025830457
FILE *pfFile = output_file_open(zFile);
3025930458
if( pfFile==0 ){
3026030459
if( cli_strcmp(zFile,"off")!=0 ){
30261
- sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
30460
+ assert( stderr!=NULL );
30461
+ sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
3026230462
}
3026330463
rc = 1;
3026430464
} else {
3026530465
output_redir(p, pfFile);
3026630466
if( zBom ) sqlite3_fputs(zBom, pfFile);
@@ -30360,10 +30560,11 @@
3036030560
sqlite3_finalize(pStmt);
3036130561
pStmt = 0;
3036230562
rc = 1;
3036330563
}
3036430564
}
30565
+ bind_prepared_stmt(p, pStmt);
3036530566
sqlite3_step(pStmt);
3036630567
sqlite3_finalize(pStmt);
3036730568
}else
3036830569
3036930570
/* .parameter unset NAME
@@ -31594,10 +31795,11 @@
3159431795
{ 0x01000000, 1, "IndexedEXpr" },
3159531796
{ 0x02000000, 1, "Coroutines" },
3159631797
{ 0x04000000, 1, "NullUnusedCols" },
3159731798
{ 0x08000000, 1, "OnePass" },
3159831799
{ 0x10000000, 1, "OrderBySubq" },
31800
+ { 0x20000000, 1, "StarQuery" },
3159931801
{ 0xffffffff, 0, "All" },
3160031802
};
3160131803
unsigned int curOpt;
3160231804
unsigned int newOpt;
3160331805
unsigned int m;
@@ -32148,11 +32350,11 @@
3214832350
goto TermScan;
3214932351
}
3215032352
break;
3215132353
case '[':
3215232354
cin = ']';
32153
- deliberate_fall_through;
32355
+ deliberate_fall_through; /* FALLTHRU */
3215432356
case '`': case '\'': case '"':
3215532357
cWait = cin;
3215632358
qss = QSS_HasDark | cWait;
3215732359
CONTINUE_PROMPT_AWAITC(pst, cin);
3215832360
goto TermScan;
@@ -32183,11 +32385,11 @@
3218332385
if(*zLine==cWait){
3218432386
/* Swallow doubled end-delimiter.*/
3218532387
++zLine;
3218632388
continue;
3218732389
}
32188
- deliberate_fall_through;
32390
+ deliberate_fall_through; /* FALLTHRU */
3218932391
case ']':
3219032392
CONTINUE_PROMPT_AWAITC(pst, 0);
3219132393
qss = QSS_SETV(qss, 0);
3219232394
goto PlainScan;
3219332395
default: assert(0);
@@ -32701,10 +32903,11 @@
3270132903
" -csv set output mode to 'csv'\n"
3270232904
#if !defined(SQLITE_OMIT_DESERIALIZE)
3270332905
" -deserialize open the database using sqlite3_deserialize()\n"
3270432906
#endif
3270532907
" -echo print inputs before execution\n"
32908
+ " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n"
3270632909
" -init FILENAME read/process named file\n"
3270732910
" -[no]header turn headers on or off\n"
3270832911
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
3270932912
" -heap SIZE Size of heap for memsys3 or memsys5\n"
3271032913
#endif
@@ -32748,11 +32951,11 @@
3274832951
#ifdef SQLITE_HAVE_ZLIB
3274932952
" -zip open the file as a ZIP Archive\n"
3275032953
#endif
3275132954
;
3275232955
static void usage(int showDetail){
32753
- sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
32956
+ sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
3275432957
"FILENAME is the name of an SQLite database. A new database is created\n"
3275532958
"if the file does not previously exist. Defaults to :memory:.\n", Argv0);
3275632959
if( showDetail ){
3275732960
sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
3275832961
}else{
@@ -33134,10 +33337,13 @@
3313433337
data.zNonce = strdup(cmdline_option_value(argc, argv, ++i));
3313533338
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
3313633339
ShellSetFlag(&data,SHFLG_TestingMode);
3313733340
}else if( cli_strcmp(z,"-safe")==0 ){
3313833341
/* no-op - catch this on the second pass */
33342
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
33343
+ /* skip over the argument */
33344
+ i++;
3313933345
}
3314033346
}
3314133347
#ifndef SQLITE_SHELL_FIDDLE
3314233348
if( !bEnableVfstrace ) verify_uninitialized();
3314333349
#endif
@@ -33233,10 +33439,29 @@
3323333439
}else if( cli_strcmp(z,"-box")==0 ){
3323433440
data.mode = MODE_Box;
3323533441
}else if( cli_strcmp(z,"-csv")==0 ){
3323633442
data.mode = MODE_Csv;
3323733443
memcpy(data.colSeparator,",",2);
33444
+ }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
33445
+ /* See similar code at tag-20250224-1 */
33446
+ const char *zEsc = argv[++i];
33447
+ int k;
33448
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
33449
+ if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
33450
+ data.eEscMode = k;
33451
+ break;
33452
+ }
33453
+ }
33454
+ if( k>=ArraySize(shell_EscModeNames) ){
33455
+ sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
33456
+ " - choices:", zEsc);
33457
+ for(k=0; k<ArraySize(shell_EscModeNames); k++){
33458
+ sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
33459
+ }
33460
+ sqlite3_fprintf(stderr, "\n");
33461
+ exit(1);
33462
+ }
3323833463
#ifdef SQLITE_HAVE_ZLIB
3323933464
}else if( cli_strcmp(z,"-zip")==0 ){
3324033465
data.openMode = SHELL_OPEN_ZIPFILE;
3324133466
#endif
3324233467
}else if( cli_strcmp(z,"-append")==0 ){
3324333468
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -355,10 +355,15 @@
355 **
356 ** The default behavior, if neither of the above is defined is to
357 ** use O_U8TEXT when writing to the Windows console (or anything
358 ** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
359 ** for all other output channels.
 
 
 
 
 
360 */
361 #if defined(SQLITE_U8TEXT_ONLY)
362 # define UseWtextForOutput(fd) 1
363 # define UseWtextForInput(fd) 1
364 # define IsConsole(fd) _isatty(_fileno(fd))
@@ -457,14 +462,14 @@
457 ** that into UTF-8. Otherwise, non-ASCII characters all get translated
458 ** into '?'.
459 */
460 wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
461 if( b1==0 ) return 0;
462 #ifndef SQLITE_USE_STDIO_FOR_CONSOLE
463 DWORD nRead = 0;
464 if( IsConsole(in)
465 && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz, &nRead, 0)
466 ){
467 b1[nRead] = 0;
468 }else
469 #endif
470 {
@@ -535,22 +540,23 @@
535 wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
536 if( b1==0 ) return 0;
537 sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
538 b1[sz] = 0;
539
540 #ifndef SQLITE_STDIO_FOR_CONSOLE
541 DWORD nWr = 0;
542 if( IsConsole(out)
543 && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
544 ){
545 /* If writing to the console, then the WriteConsoleW() is all we
546 ** need to do. */
547 }else
548 #endif
549 {
550 /* For non-console I/O, or if SQLITE_USE_STDIO_FOR_CONSOLE is defined
551 ** then write using the standard library. */
 
552 _setmode(_fileno(out), _O_U8TEXT);
553 if( UseBinaryWText(out) ){
554 piecemealOutput(b1, sz, out);
555 }else{
556 fputws(b1, out);
@@ -843,11 +849,11 @@
843
844 /*
845 ** Prompt strings. Initialized in main. Settable with
846 ** .prompt main continue
847 */
848 #define PROMPT_LEN_MAX 20
849 /* First line prompt. default: "sqlite> " */
850 static char mainPrompt[PROMPT_LEN_MAX];
851 /* Continuation prompt. default: " ...> " */
852 static char continuePrompt[PROMPT_LEN_MAX];
853
@@ -5289,31 +5295,34 @@
5289 u8 bdp = BX_DV_PROTO(c);
5290 switch( bdp ){
5291 case ND:
5292 /* Treat dark non-digits as pad, but they terminate decode too. */
5293 ncIn = 0;
5294 deliberate_fall_through;
5295 case WS:
5296 /* Treat whitespace as pad and terminate this group.*/
5297 nti = nac;
5298 deliberate_fall_through;
5299 case PC:
5300 bdp = 0;
5301 --nbo;
5302 deliberate_fall_through;
5303 default: /* bdp is the digit value. */
5304 qv = qv<<6 | bdp;
5305 break;
5306 }
5307 }
5308 switch( nbo ){
5309 case 3:
5310 pOut[2] = (qv) & 0xff;
 
5311 case 2:
5312 pOut[1] = (qv>>8) & 0xff;
 
5313 case 1:
5314 pOut[0] = (qv>>16) & 0xff;
 
5315 }
5316 pOut += nbo;
5317 }
5318 return pOut;
5319 }
@@ -5644,16 +5653,20 @@
5644 }
5645 nbo -= nti; /* Adjust for early (non-digit) end of group. */
5646 switch( nbo ){
5647 case 4:
5648 *pOut++ = (qv >> 24)&0xff;
 
5649 case 3:
5650 *pOut++ = (qv >> 16)&0xff;
 
5651 case 2:
5652 *pOut++ = (qv >> 8)&0xff;
 
5653 case 1:
5654 *pOut++ = qv&0xff;
 
5655 case 0:
5656 break;
5657 }
5658 }
5659 return pOut;
@@ -7692,11 +7705,12 @@
7692
7693 /* Free and reclaim all the memory used by a previously compiled
7694 ** regular expression. Applications should invoke this routine once
7695 ** for every call to re_compile() to avoid memory leaks.
7696 */
7697 static void re_free(ReCompiled *pRe){
 
7698 if( pRe ){
7699 sqlite3_free(pRe->aOp);
7700 sqlite3_free(pRe->aArg);
7701 sqlite3_free(pRe);
7702 }
@@ -8358,11 +8372,11 @@
8358 LPWSTR zUnicodeName;
8359 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
8360
8361 GetSystemTime(&currentTime);
8362 SystemTimeToFileTime(&currentTime, &lastAccess);
8363 intervals = Int32x32To64(mtime, 10000000) + 116444736000000000;
8364 lastWrite.dwLowDateTime = (DWORD)intervals;
8365 lastWrite.dwHighDateTime = intervals >> 32;
8366 zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
8367 if( zUnicodeName==0 ){
8368 return 1;
@@ -16344,10 +16358,11 @@
16344 #define VTR_DLCLOSE 0x00800000
16345 #define VTR_RAND 0x01000000
16346 #define VTR_SLEEP 0x02000000
16347 #define VTR_CURTIME 0x04000000
16348 #define VTR_LASTERR 0x08000000
 
16349
16350 /*
16351 ** Method declarations for vfstrace_file.
16352 */
16353 static int vfstraceClose(sqlite3_file*);
@@ -16773,10 +16788,11 @@
16773 { "randomness", VTR_RAND },
16774 { "sleep", VTR_SLEEP },
16775 { "currenttime", VTR_CURTIME },
16776 { "currenttimeint64", VTR_CURTIME },
16777 { "getlasterror", VTR_LASTERR },
 
16778 };
16779 int onOff = 1;
16780 while( zArg[0] ){
16781 int jj, n;
16782 while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
@@ -17000,11 +17016,32 @@
17000 pInfo->zVfsName, p->zFName, delFlag);
17001 rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
17002 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17003 return rc;
17004 }
17005
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17006
17007
17008 /*
17009 ** Open an vfstrace file handle.
17010 */
@@ -17047,10 +17084,14 @@
17047 pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
17048 pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
17049 pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
17050 pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
17051 }
 
 
 
 
17052 pFile->pMethods = pNew;
17053 }
17054 vfstrace_print_errcode(pInfo, " -> %s", rc);
17055 if( pOutFlags ){
17056 vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
@@ -17162,11 +17203,11 @@
17162 */
17163 static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
17164 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17165 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17166 vfstraceOnOff(pInfo, VTR_DLCLOSE);
17167 vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
17168 pRoot->xDlClose(pRoot, pHandle);
17169 }
17170
17171 /*
17172 ** Populate the buffer pointed to by zBufOut with nByte bytes of
@@ -21569,10 +21610,11 @@
21569 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
21570 u8 bSafeMode; /* True to prohibit unsafe operations */
21571 u8 bSafeModePersist; /* The long-term value of bSafeMode */
21572 u8 eRestoreState; /* See comments above doAutoDetectRestore() */
21573 u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
 
21574 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
21575 unsigned statsOn; /* True to display memory stats before each finalize */
21576 unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
21577 int inputNesting; /* Track nesting level of .read and other redirects */
21578 int outCount; /* Revert to stdout when reaching zero */
@@ -21669,10 +21711,18 @@
21669 #define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
21670 ** callback limit is reached, and for each
21671 ** top-level SQL statement */
21672 #define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
21673
 
 
 
 
 
 
 
 
21674 /*
21675 ** These are the allowed shellFlgs values
21676 */
21677 #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
21678 #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
@@ -22006,63 +22056,79 @@
22006 sqlite3_fprintf(out, "X'%s'", zStr);
22007 sqlite3_free(zStr);
22008 }
22009
22010 /*
22011 ** Find a string that is not found anywhere in z[]. Return a pointer
22012 ** to that string.
22013 **
22014 ** Try to use zA and zB first. If both of those are already found in z[]
22015 ** then make up some string and store it in the buffer zBuf.
22016 */
22017 static const char *unused_string(
22018 const char *z, /* Result must not appear anywhere in z */
22019 const char *zA, const char *zB, /* Try these first */
22020 char *zBuf /* Space to store a generated string */
22021 ){
22022 unsigned i = 0;
22023 if( strstr(z, zA)==0 ) return zA;
22024 if( strstr(z, zB)==0 ) return zB;
22025 do{
22026 sqlite3_snprintf(20,zBuf,"(%s%u)", zA, i++);
22027 }while( strstr(z,zBuf)!=0 );
22028 return zBuf;
22029 }
22030
22031 /*
22032 ** Output the given string as a quoted string using SQL quoting conventions.
22033 **
22034 ** See also: output_quoted_escaped_string()
22035 */
22036 static void output_quoted_string(ShellState *p, const char *z){
22037 int i;
22038 char c;
22039 FILE *out = p->out;
22040 sqlite3_fsetmode(out, _O_BINARY);
22041 if( z==0 ) return;
22042 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22043 if( c==0 ){
 
 
 
 
 
 
 
 
 
22044 sqlite3_fprintf(out, "'%s'",z);
 
 
 
 
22045 }else{
22046 sqlite3_fputs("'", out);
 
 
 
 
22047 while( *z ){
22048 for(i=0; (c = z[i])!=0 && c!='\''; i++){}
22049 if( c=='\'' ) i++;
 
 
 
 
 
22050 if( i ){
22051 sqlite3_fprintf(out, "%.*s", i, z);
22052 z += i;
22053 }
 
22054 if( c=='\'' ){
22055 sqlite3_fputs("'", out);
22056 continue;
22057 }
22058 if( c==0 ){
22059 break;
22060 }
22061 z++;
22062 }
22063 sqlite3_fputs("'", out);
 
 
 
 
22064 }
22065 setCrlfMode(p);
22066 }
22067
22068 /*
@@ -22073,65 +22139,19 @@
22073 **
22074 ** This is like output_quoted_string() but with the addition of the \r\n
22075 ** escape mechanism.
22076 */
22077 static void output_quoted_escaped_string(ShellState *p, const char *z){
22078 int i;
22079 char c;
22080 FILE *out = p->out;
22081 sqlite3_fsetmode(out, _O_BINARY);
22082 for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
22083 if( c==0 ){
22084 sqlite3_fprintf(out, "'%s'",z);
22085 }else{
22086 const char *zNL = 0;
22087 const char *zCR = 0;
22088 int nNL = 0;
22089 int nCR = 0;
22090 char zBuf1[20], zBuf2[20];
22091 for(i=0; z[i]; i++){
22092 if( z[i]=='\n' ) nNL++;
22093 if( z[i]=='\r' ) nCR++;
22094 }
22095 if( nNL ){
22096 sqlite3_fputs("replace(", out);
22097 zNL = unused_string(z, "\\n", "\\012", zBuf1);
22098 }
22099 if( nCR ){
22100 sqlite3_fputs("replace(", out);
22101 zCR = unused_string(z, "\\r", "\\015", zBuf2);
22102 }
22103 sqlite3_fputs("'", out);
22104 while( *z ){
22105 for(i=0; (c = z[i])!=0 && c!='\n' && c!='\r' && c!='\''; i++){}
22106 if( c=='\'' ) i++;
22107 if( i ){
22108 sqlite3_fprintf(out, "%.*s", i, z);
22109 z += i;
22110 }
22111 if( c=='\'' ){
22112 sqlite3_fputs("'", out);
22113 continue;
22114 }
22115 if( c==0 ){
22116 break;
22117 }
22118 z++;
22119 if( c=='\n' ){
22120 sqlite3_fputs(zNL, out);
22121 continue;
22122 }
22123 sqlite3_fputs(zCR, out);
22124 }
22125 sqlite3_fputs("'", out);
22126 if( nCR ){
22127 sqlite3_fprintf(out, ",'%s',char(13))", zCR);
22128 }
22129 if( nNL ){
22130 sqlite3_fprintf(out, ",'%s',char(10))", zNL);
22131 }
22132 }
22133 setCrlfMode(p);
22134 }
22135
22136 /*
22137 ** Find earliest of chars within s specified in zAny.
@@ -22276,10 +22296,97 @@
22276 sqlite3_fputs(ace+1, out);
22277 }
22278 }
22279 sqlite3_fputs(zq, out);
22280 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22281
22282 /*
22283 ** Output the given string with characters that are special to
22284 ** HTML escaped.
22285 */
@@ -22720,12 +22827,16 @@
22720 int len = strlen30(azCol[i] ? azCol[i] : "");
22721 if( len>w ) w = len;
22722 }
22723 if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
22724 for(i=0; i<nArg; i++){
 
 
 
22725 sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
22726 azArg[i] ? azArg[i] : p->nullValue, p->rowSeparator);
 
22727 }
22728 break;
22729 }
22730 case MODE_ScanExp:
22731 case MODE_Explain: {
@@ -22853,19 +22964,27 @@
22853 break;
22854 }
22855 case MODE_List: {
22856 if( p->cnt++==0 && p->showHeader ){
22857 for(i=0; i<nArg; i++){
22858 sqlite3_fprintf(p->out, "%s%s", azCol[i],
 
 
 
22859 i==nArg-1 ? p->rowSeparator : p->colSeparator);
 
22860 }
22861 }
22862 if( azArg==0 ) break;
22863 for(i=0; i<nArg; i++){
22864 char *z = azArg[i];
 
 
22865 if( z==0 ) z = p->nullValue;
22866 sqlite3_fputs(z, p->out);
 
 
22867 sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
22868 }
22869 break;
22870 }
22871 case MODE_Www:
@@ -23980,10 +24099,11 @@
23980 ** from malloc()) of that first line, which caller should free sometime.
23981 ** Write anything to display on the next line into *pzTail. If this is
23982 ** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
23983 */
23984 static char *translateForDisplayAndDup(
 
23985 const unsigned char *z, /* Input text to be transformed */
23986 const unsigned char **pzTail, /* OUT: Tail of the input for next line */
23987 int mxWidth, /* Max width. 0 means no limit */
23988 u8 bWordWrap /* If true, avoid breaking mid-word */
23989 ){
@@ -24014,19 +24134,22 @@
24014 n++;
24015 i++;
24016 j++;
24017 continue;
24018 }
 
24019 if( c=='\t' ){
24020 do{
24021 n++;
24022 j++;
24023 }while( (n&7)!=0 && n<mxWidth );
24024 i++;
24025 continue;
24026 }
24027 break;
 
 
24028 }
24029 if( n>=mxWidth && bWordWrap ){
24030 /* Perhaps try to back up to a better place to break the line */
24031 for(k=i; k>i/2; k--){
24032 if( isspace(z[k-1]) ) break;
@@ -24069,23 +24192,48 @@
24069 if( c>=' ' ){
24070 n++;
24071 zOut[j++] = z[i++];
24072 continue;
24073 }
 
24074 if( z[i]=='\t' ){
24075 do{
24076 n++;
24077 zOut[j++] = ' ';
24078 }while( (n&7)!=0 && n<mxWidth );
24079 i++;
24080 continue;
24081 }
24082 break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24083 }
24084 zOut[j] = 0;
24085 return (char*)zOut;
24086 }
 
 
 
 
 
 
 
 
 
 
24087
24088 /* Extract the value of the i-th current column for pStmt as an SQL literal
24089 ** value. Memory is obtained from sqlite3_malloc64() and must be freed by
24090 ** the caller.
24091 */
@@ -24097,11 +24245,12 @@
24097 case SQLITE_INTEGER:
24098 case SQLITE_FLOAT: {
24099 return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
24100 }
24101 case SQLITE_TEXT: {
24102 return sqlite3_mprintf("%Q",sqlite3_column_text(pStmt,i));
 
24103 }
24104 case SQLITE_BLOB: {
24105 int j;
24106 sqlite3_str *pStr = sqlite3_str_new(0);
24107 const unsigned char *a = sqlite3_column_blob(pStmt,i);
@@ -24189,11 +24338,11 @@
24189 wx = p->cmOpts.iWrap;
24190 }
24191 if( wx<0 ) wx = -wx;
24192 uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
24193 if( uz==0 ) uz = (u8*)"";
24194 azData[i] = translateForDisplayAndDup(uz, &zNotUsed, wx, bw);
24195 }
24196 do{
24197 int useNextLine = bNextLine;
24198 bNextLine = 0;
24199 if( (nRow+2)*nColumn >= nAlloc ){
@@ -24213,19 +24362,20 @@
24213 if( wx<0 ) wx = -wx;
24214 if( useNextLine ){
24215 uz = azNextLine[i];
24216 if( uz==0 ) uz = (u8*)zEmpty;
24217 }else if( p->cmOpts.bQuote ){
 
24218 sqlite3_free(azQuoted[i]);
24219 azQuoted[i] = quoted_column(pStmt,i);
24220 uz = (const unsigned char*)azQuoted[i];
24221 }else{
24222 uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
24223 if( uz==0 ) uz = (u8*)zShowNull;
24224 }
24225 azData[nRow*nColumn + i]
24226 = translateForDisplayAndDup(uz, &azNextLine[i], wx, bw);
24227 if( azNextLine[i] ){
24228 bNextLine = 1;
24229 abRowDiv[nRow-1] = 0;
24230 bMultiLineRowExists = 1;
24231 }
@@ -25144,11 +25294,11 @@
25144 #if !defined(SQLITE_SHELL_FIDDLE)
25145 ".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout",
25146 #else
25147 ".log on|off Turn logging on or off.",
25148 #endif
25149 ".mode MODE ?OPTIONS? Set output mode",
25150 " MODE is one of:",
25151 " ascii Columns/rows delimited by 0x1F and 0x1E",
25152 " box Tables using unicode box-drawing characters",
25153 " csv Comma-separated values",
25154 " column Output in columns. (See .width)",
@@ -25162,10 +25312,11 @@
25162 " quote Escape answers as for SQL",
25163 " table ASCII-art table",
25164 " tabs Tab-separated values",
25165 " tcl TCL list elements",
25166 " OPTIONS: (for columnar modes or insert mode):",
 
25167 " --wrap N Wrap output lines to no longer than N characters",
25168 " --wordwrap B Wrap or not at word boundaries per B (on/off)",
25169 " --ww Shorthand for \"--wordwrap 1\"",
25170 " --quote Quote output text as SQL literals",
25171 " --noquote Do not quote output text",
@@ -27460,11 +27611,11 @@
27460 case AR_SWITCH_VERBOSE:
27461 pAr->bVerbose = 1;
27462 break;
27463 case AR_SWITCH_APPEND:
27464 pAr->bAppend = 1;
27465 deliberate_fall_through;
27466 case AR_SWITCH_FILE:
27467 pAr->zFile = zArg;
27468 break;
27469 case AR_SWITCH_DIRECTORY:
27470 pAr->zDir = zArg;
@@ -28848,10 +28999,13 @@
28848 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
28849 static const struct DbConfigChoices {
28850 const char *zName;
28851 int op;
28852 } aDbConfig[] = {
 
 
 
28853 { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
28854 { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
28855 { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
28856 { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
28857 { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
@@ -29899,28 +30053,56 @@
29899
29900 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
29901 const char *zMode = 0;
29902 const char *zTabname = 0;
29903 int i, n2;
 
29904 ColModeOpts cmOpts = ColModeOpts_default;
29905 for(i=1; i<nArg; i++){
29906 const char *z = azArg[i];
29907 if( optionMatch(z,"wrap") && i+1<nArg ){
29908 cmOpts.iWrap = integerValue(azArg[++i]);
 
29909 }else if( optionMatch(z,"ww") ){
29910 cmOpts.bWordWrap = 1;
 
29911 }else if( optionMatch(z,"wordwrap") && i+1<nArg ){
29912 cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
 
29913 }else if( optionMatch(z,"quote") ){
29914 cmOpts.bQuote = 1;
 
29915 }else if( optionMatch(z,"noquote") ){
29916 cmOpts.bQuote = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29917 }else if( zMode==0 ){
29918 zMode = z;
29919 /* Apply defaults for qbox pseudo-mode. If that
29920 * overwrites already-set values, user was informed of this.
29921 */
 
29922 if( cli_strcmp(z, "qbox")==0 ){
29923 ColModeOpts cmo = ColModeOpts_default_qbox;
29924 zMode = "box";
29925 cmOpts = cmo;
29926 }
@@ -29927,10 +30109,11 @@
29927 }else if( zTabname==0 ){
29928 zTabname = z;
29929 }else if( z[0]=='-' ){
29930 sqlite3_fprintf(stderr,"unknown option: %s\n", z);
29931 eputz("options:\n"
 
29932 " --noquote\n"
29933 " --quote\n"
29934 " --wordwrap on/off\n"
29935 " --wrap N\n"
29936 " --ww\n");
@@ -29940,24 +30123,33 @@
29940 sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
29941 rc = 1;
29942 goto meta_command_exit;
29943 }
29944 }
29945 if( zMode==0 ){
29946 if( p->mode==MODE_Column
29947 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
29948 ){
29949 sqlite3_fprintf(p->out,
29950 "current output mode: %s --wrap %d --wordwrap %s --%squote\n",
 
29951 modeDescr[p->mode], p->cmOpts.iWrap,
29952 p->cmOpts.bWordWrap ? "on" : "off",
29953 p->cmOpts.bQuote ? "" : "no");
 
 
29954 }else{
29955 sqlite3_fprintf(p->out,
29956 "current output mode: %s\n", modeDescr[p->mode]);
 
 
 
29957 }
 
 
29958 zMode = modeDescr[p->mode];
 
29959 }
29960 n2 = strlen30(zMode);
29961 if( cli_strncmp(zMode,"lines",n2)==0 ){
29962 p->mode = MODE_Line;
29963 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
@@ -29986,10 +30178,15 @@
29986 p->mode = MODE_List;
29987 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
29988 }else if( cli_strncmp(zMode,"insert",n2)==0 ){
29989 p->mode = MODE_Insert;
29990 set_table_name(p, zTabname ? zTabname : "table");
 
 
 
 
 
29991 }else if( cli_strncmp(zMode,"quote",n2)==0 ){
29992 p->mode = MODE_Quote;
29993 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
29994 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
29995 }else if( cli_strncmp(zMode,"ascii",n2)==0 ){
@@ -30202,10 +30399,11 @@
30202 }
30203 }
30204 if( zFile==0 ){
30205 zFile = sqlite3_mprintf("stdout");
30206 }
 
30207 if( bOnce ){
30208 p->outCount = 2;
30209 }else{
30210 p->outCount = 0;
30211 }
@@ -30244,10 +30442,11 @@
30244 rc = 1;
30245 output_redir(p, stdout);
30246 #else
30247 FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
30248 if( pfPipe==0 ){
 
30249 sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
30250 rc = 1;
30251 }else{
30252 output_redir(p, pfPipe);
30253 if( zBom ) sqlite3_fputs(zBom, pfPipe);
@@ -30256,11 +30455,12 @@
30256 #endif
30257 }else{
30258 FILE *pfFile = output_file_open(zFile);
30259 if( pfFile==0 ){
30260 if( cli_strcmp(zFile,"off")!=0 ){
30261 sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
 
30262 }
30263 rc = 1;
30264 } else {
30265 output_redir(p, pfFile);
30266 if( zBom ) sqlite3_fputs(zBom, pfFile);
@@ -30360,10 +30560,11 @@
30360 sqlite3_finalize(pStmt);
30361 pStmt = 0;
30362 rc = 1;
30363 }
30364 }
 
30365 sqlite3_step(pStmt);
30366 sqlite3_finalize(pStmt);
30367 }else
30368
30369 /* .parameter unset NAME
@@ -31594,10 +31795,11 @@
31594 { 0x01000000, 1, "IndexedEXpr" },
31595 { 0x02000000, 1, "Coroutines" },
31596 { 0x04000000, 1, "NullUnusedCols" },
31597 { 0x08000000, 1, "OnePass" },
31598 { 0x10000000, 1, "OrderBySubq" },
 
31599 { 0xffffffff, 0, "All" },
31600 };
31601 unsigned int curOpt;
31602 unsigned int newOpt;
31603 unsigned int m;
@@ -32148,11 +32350,11 @@
32148 goto TermScan;
32149 }
32150 break;
32151 case '[':
32152 cin = ']';
32153 deliberate_fall_through;
32154 case '`': case '\'': case '"':
32155 cWait = cin;
32156 qss = QSS_HasDark | cWait;
32157 CONTINUE_PROMPT_AWAITC(pst, cin);
32158 goto TermScan;
@@ -32183,11 +32385,11 @@
32183 if(*zLine==cWait){
32184 /* Swallow doubled end-delimiter.*/
32185 ++zLine;
32186 continue;
32187 }
32188 deliberate_fall_through;
32189 case ']':
32190 CONTINUE_PROMPT_AWAITC(pst, 0);
32191 qss = QSS_SETV(qss, 0);
32192 goto PlainScan;
32193 default: assert(0);
@@ -32701,10 +32903,11 @@
32701 " -csv set output mode to 'csv'\n"
32702 #if !defined(SQLITE_OMIT_DESERIALIZE)
32703 " -deserialize open the database using sqlite3_deserialize()\n"
32704 #endif
32705 " -echo print inputs before execution\n"
 
32706 " -init FILENAME read/process named file\n"
32707 " -[no]header turn headers on or off\n"
32708 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
32709 " -heap SIZE Size of heap for memsys3 or memsys5\n"
32710 #endif
@@ -32748,11 +32951,11 @@
32748 #ifdef SQLITE_HAVE_ZLIB
32749 " -zip open the file as a ZIP Archive\n"
32750 #endif
32751 ;
32752 static void usage(int showDetail){
32753 sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL]]\n"
32754 "FILENAME is the name of an SQLite database. A new database is created\n"
32755 "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
32756 if( showDetail ){
32757 sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
32758 }else{
@@ -33134,10 +33337,13 @@
33134 data.zNonce = strdup(cmdline_option_value(argc, argv, ++i));
33135 }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
33136 ShellSetFlag(&data,SHFLG_TestingMode);
33137 }else if( cli_strcmp(z,"-safe")==0 ){
33138 /* no-op - catch this on the second pass */
 
 
 
33139 }
33140 }
33141 #ifndef SQLITE_SHELL_FIDDLE
33142 if( !bEnableVfstrace ) verify_uninitialized();
33143 #endif
@@ -33233,10 +33439,29 @@
33233 }else if( cli_strcmp(z,"-box")==0 ){
33234 data.mode = MODE_Box;
33235 }else if( cli_strcmp(z,"-csv")==0 ){
33236 data.mode = MODE_Csv;
33237 memcpy(data.colSeparator,",",2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33238 #ifdef SQLITE_HAVE_ZLIB
33239 }else if( cli_strcmp(z,"-zip")==0 ){
33240 data.openMode = SHELL_OPEN_ZIPFILE;
33241 #endif
33242 }else if( cli_strcmp(z,"-append")==0 ){
33243
--- extsrc/shell.c
+++ extsrc/shell.c
@@ -355,10 +355,15 @@
355 **
356 ** The default behavior, if neither of the above is defined is to
357 ** use O_U8TEXT when writing to the Windows console (or anything
358 ** else for which _isatty() returns true) and to use O_BINARY or O_TEXT
359 ** for all other output channels.
360 **
361 ** The SQLITE_USE_W32_FOR_CONSOLE_IO macro is also available. If
362 ** defined, it forces the use of Win32 APIs for all console I/O, both
363 ** input and output. This is necessary for some non-Microsoft run-times
364 ** that implement stdio differently from Microsoft/Visual-Studio.
365 */
366 #if defined(SQLITE_U8TEXT_ONLY)
367 # define UseWtextForOutput(fd) 1
368 # define UseWtextForInput(fd) 1
369 # define IsConsole(fd) _isatty(_fileno(fd))
@@ -457,14 +462,14 @@
462 ** that into UTF-8. Otherwise, non-ASCII characters all get translated
463 ** into '?'.
464 */
465 wchar_t *b1 = sqlite3_malloc( sz*sizeof(wchar_t) );
466 if( b1==0 ) return 0;
467 #ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
468 DWORD nRead = 0;
469 if( IsConsole(in)
470 && ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), b1, sz-1, &nRead, 0)
471 ){
472 b1[nRead] = 0;
473 }else
474 #endif
475 {
@@ -535,22 +540,23 @@
540 wchar_t *b1 = sqlite3_malloc( (sz+1)*sizeof(wchar_t) );
541 if( b1==0 ) return 0;
542 sz = MultiByteToWideChar(CP_UTF8, 0, z, sz, b1, sz);
543 b1[sz] = 0;
544
545 #ifdef SQLITE_USE_W32_FOR_CONSOLE_IO
546 DWORD nWr = 0;
547 if( IsConsole(out)
548 && WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),b1,sz,&nWr,0)
549 ){
550 /* If writing to the console, then the WriteConsoleW() is all we
551 ** need to do. */
552 }else
553 #endif
554 {
555 /* As long as SQLITE_USE_W32_FOR_CONSOLE_IO is not defined, or for
556 ** non-console I/O even if that macro is defined, write using the
557 ** standard library. */
558 _setmode(_fileno(out), _O_U8TEXT);
559 if( UseBinaryWText(out) ){
560 piecemealOutput(b1, sz, out);
561 }else{
562 fputws(b1, out);
@@ -843,11 +849,11 @@
849
850 /*
851 ** Prompt strings. Initialized in main. Settable with
852 ** .prompt main continue
853 */
854 #define PROMPT_LEN_MAX 128
855 /* First line prompt. default: "sqlite> " */
856 static char mainPrompt[PROMPT_LEN_MAX];
857 /* Continuation prompt. default: " ...> " */
858 static char continuePrompt[PROMPT_LEN_MAX];
859
@@ -5289,31 +5295,34 @@
5295 u8 bdp = BX_DV_PROTO(c);
5296 switch( bdp ){
5297 case ND:
5298 /* Treat dark non-digits as pad, but they terminate decode too. */
5299 ncIn = 0;
5300 deliberate_fall_through; /* FALLTHRU */
5301 case WS:
5302 /* Treat whitespace as pad and terminate this group.*/
5303 nti = nac;
5304 deliberate_fall_through; /* FALLTHRU */
5305 case PC:
5306 bdp = 0;
5307 --nbo;
5308 deliberate_fall_through; /* FALLTHRU */
5309 default: /* bdp is the digit value. */
5310 qv = qv<<6 | bdp;
5311 break;
5312 }
5313 }
5314 switch( nbo ){
5315 case 3:
5316 pOut[2] = (qv) & 0xff;
5317 deliberate_fall_through; /* FALLTHRU */
5318 case 2:
5319 pOut[1] = (qv>>8) & 0xff;
5320 deliberate_fall_through; /* FALLTHRU */
5321 case 1:
5322 pOut[0] = (qv>>16) & 0xff;
5323 break;
5324 }
5325 pOut += nbo;
5326 }
5327 return pOut;
5328 }
@@ -5644,16 +5653,20 @@
5653 }
5654 nbo -= nti; /* Adjust for early (non-digit) end of group. */
5655 switch( nbo ){
5656 case 4:
5657 *pOut++ = (qv >> 24)&0xff;
5658 /* FALLTHRU */
5659 case 3:
5660 *pOut++ = (qv >> 16)&0xff;
5661 /* FALLTHRU */
5662 case 2:
5663 *pOut++ = (qv >> 8)&0xff;
5664 /* FALLTHRU */
5665 case 1:
5666 *pOut++ = qv&0xff;
5667 /* FALLTHRU */
5668 case 0:
5669 break;
5670 }
5671 }
5672 return pOut;
@@ -7692,11 +7705,12 @@
7705
7706 /* Free and reclaim all the memory used by a previously compiled
7707 ** regular expression. Applications should invoke this routine once
7708 ** for every call to re_compile() to avoid memory leaks.
7709 */
7710 static void re_free(void *p){
7711 ReCompiled *pRe = (ReCompiled*)p;
7712 if( pRe ){
7713 sqlite3_free(pRe->aOp);
7714 sqlite3_free(pRe->aArg);
7715 sqlite3_free(pRe);
7716 }
@@ -8358,11 +8372,11 @@
8372 LPWSTR zUnicodeName;
8373 extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*);
8374
8375 GetSystemTime(&currentTime);
8376 SystemTimeToFileTime(&currentTime, &lastAccess);
8377 intervals = (mtime*10000000) + 116444736000000000;
8378 lastWrite.dwLowDateTime = (DWORD)intervals;
8379 lastWrite.dwHighDateTime = intervals >> 32;
8380 zUnicodeName = sqlite3_win32_utf8_to_unicode(zFile);
8381 if( zUnicodeName==0 ){
8382 return 1;
@@ -16344,10 +16358,11 @@
16358 #define VTR_DLCLOSE 0x00800000
16359 #define VTR_RAND 0x01000000
16360 #define VTR_SLEEP 0x02000000
16361 #define VTR_CURTIME 0x04000000
16362 #define VTR_LASTERR 0x08000000
16363 #define VTR_FETCH 0x10000000 /* Also coverse xUnfetch */
16364
16365 /*
16366 ** Method declarations for vfstrace_file.
16367 */
16368 static int vfstraceClose(sqlite3_file*);
@@ -16773,10 +16788,11 @@
16788 { "randomness", VTR_RAND },
16789 { "sleep", VTR_SLEEP },
16790 { "currenttime", VTR_CURTIME },
16791 { "currenttimeint64", VTR_CURTIME },
16792 { "getlasterror", VTR_LASTERR },
16793 { "fetch", VTR_FETCH },
16794 };
16795 int onOff = 1;
16796 while( zArg[0] ){
16797 int jj, n;
16798 while( zArg[0]!=0 && zArg[0]!='-' && zArg[0]!='+'
@@ -17000,11 +17016,32 @@
17016 pInfo->zVfsName, p->zFName, delFlag);
17017 rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
17018 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17019 return rc;
17020 }
17021 static int vfstraceFetch(sqlite3_file *pFile, i64 iOff, int nAmt, void **pptr){
17022 vfstrace_file *p = (vfstrace_file *)pFile;
17023 vfstrace_info *pInfo = p->pInfo;
17024 int rc;
17025 vfstraceOnOff(pInfo, VTR_FETCH);
17026 vfstrace_printf(pInfo, "%s.xFetch(%s,iOff=%lld,nAmt=%d,p=%p)",
17027 pInfo->zVfsName, p->zFName, iOff, nAmt, *pptr);
17028 rc = p->pReal->pMethods->xFetch(p->pReal, iOff, nAmt, pptr);
17029 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17030 return rc;
17031 }
17032 static int vfstraceUnfetch(sqlite3_file *pFile, i64 iOff, void *ptr){
17033 vfstrace_file *p = (vfstrace_file *)pFile;
17034 vfstrace_info *pInfo = p->pInfo;
17035 int rc;
17036 vfstraceOnOff(pInfo, VTR_FETCH);
17037 vfstrace_printf(pInfo, "%s.xUnfetch(%s,iOff=%lld,p=%p)",
17038 pInfo->zVfsName, p->zFName, iOff, ptr);
17039 rc = p->pReal->pMethods->xUnfetch(p->pReal, iOff, ptr);
17040 vfstrace_print_errcode(pInfo, " -> %s\n", rc);
17041 return rc;
17042 }
17043
17044
17045 /*
17046 ** Open an vfstrace file handle.
17047 */
@@ -17047,10 +17084,14 @@
17084 pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
17085 pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
17086 pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
17087 pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
17088 }
17089 if( pNew->iVersion>=3 ){
17090 pNew->xFetch = pSub->xFetch ? vfstraceFetch : 0;
17091 pNew->xUnfetch = pSub->xUnfetch ? vfstraceUnfetch : 0;
17092 }
17093 pFile->pMethods = pNew;
17094 }
17095 vfstrace_print_errcode(pInfo, " -> %s", rc);
17096 if( pOutFlags ){
17097 vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
@@ -17162,11 +17203,11 @@
17203 */
17204 static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
17205 vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
17206 sqlite3_vfs *pRoot = pInfo->pRootVfs;
17207 vfstraceOnOff(pInfo, VTR_DLCLOSE);
17208 vfstrace_printf(pInfo, "%s.xDlClose()\n", pInfo->zVfsName);
17209 pRoot->xDlClose(pRoot, pHandle);
17210 }
17211
17212 /*
17213 ** Populate the buffer pointed to by zBufOut with nByte bytes of
@@ -21569,10 +21610,11 @@
21610 u8 eTraceType; /* SHELL_TRACE_* value for type of trace */
21611 u8 bSafeMode; /* True to prohibit unsafe operations */
21612 u8 bSafeModePersist; /* The long-term value of bSafeMode */
21613 u8 eRestoreState; /* See comments above doAutoDetectRestore() */
21614 u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */
21615 u8 eEscMode; /* Escape mode for text output */
21616 ColModeOpts cmOpts; /* Option values affecting columnar mode output */
21617 unsigned statsOn; /* True to display memory stats before each finalize */
21618 unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */
21619 int inputNesting; /* Track nesting level of .read and other redirects */
21620 int outCount; /* Revert to stdout when reaching zero */
@@ -21669,10 +21711,18 @@
21711 #define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
21712 ** callback limit is reached, and for each
21713 ** top-level SQL statement */
21714 #define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
21715
21716 /* Allowed values for ShellState.eEscMode
21717 */
21718 #define SHELL_ESC_SYMBOL 0 /* Substitute U+2400 graphics */
21719 #define SHELL_ESC_ASCII 1 /* Substitute ^Y for X where Y=X+0x40 */
21720 #define SHELL_ESC_OFF 2 /* Send characters verbatim */
21721
21722 static const char *shell_EscModeNames[] = { "symbol", "ascii", "off" };
21723
21724 /*
21725 ** These are the allowed shellFlgs values
21726 */
21727 #define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
21728 #define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
@@ -22006,63 +22056,79 @@
22056 sqlite3_fprintf(out, "X'%s'", zStr);
22057 sqlite3_free(zStr);
22058 }
22059
22060 /*
22061 ** Output the given string as a quoted string using SQL quoting conventions:
22062 **
22063 ** (1) Single quotes (') within the string are doubled
22064 ** (2) The whle string is enclosed in '...'
22065 ** (3) Control characters other than \n, \t, and \r\n are escaped
22066 ** using \u00XX notation and if such substitutions occur,
22067 ** the whole string is enclosed in unistr('...') instead of '...'.
22068 **
22069 ** Step (3) is omitted if the control-character escape mode is OFF.
22070 **
22071 ** See also: output_quoted_escaped_string() which does the same except
22072 ** that it does not make exceptions for \n, \t, and \r\n in step (3).
22073 */
22074 static void output_quoted_string(ShellState *p, const char *zInX){
22075 int i;
22076 int needUnistr = 0;
22077 int needDblQuote = 0;
22078 const unsigned char *z = (const unsigned char*)zInX;
22079 unsigned char c;
 
 
 
 
 
 
 
 
 
22080 FILE *out = p->out;
22081 sqlite3_fsetmode(out, _O_BINARY);
22082 if( z==0 ) return;
22083 for(i=0; (c = z[i])!=0; i++){
22084 if( c=='\'' ){ needDblQuote = 1; }
22085 if( c>0x1f ) continue;
22086 if( c=='\t' || c=='\n' ) continue;
22087 if( c=='\r' && z[i+1]=='\n' ) continue;
22088 needUnistr = 1;
22089 break;
22090 }
22091 if( (needDblQuote==0 && needUnistr==0)
22092 || (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF)
22093 ){
22094 sqlite3_fprintf(out, "'%s'",z);
22095 }else if( p->eEscMode==SHELL_ESC_OFF ){
22096 char *zEncoded = sqlite3_mprintf("%Q", z);
22097 sqlite3_fputs(zEncoded, out);
22098 sqlite3_free(zEncoded);
22099 }else{
22100 if( needUnistr ){
22101 sqlite3_fputs("unistr('", out);
22102 }else{
22103 sqlite3_fputs("'", out);
22104 }
22105 while( *z ){
22106 for(i=0; (c = z[i])!=0; i++){
22107 if( c=='\'' ) break;
22108 if( c>0x1f ) continue;
22109 if( c=='\t' || c=='\n' ) continue;
22110 if( c=='\r' && z[i+1]=='\n' ) continue;
22111 break;
22112 }
22113 if( i ){
22114 sqlite3_fprintf(out, "%.*s", i, z);
22115 z += i;
22116 }
22117 if( c==0 ) break;
22118 if( c=='\'' ){
22119 sqlite3_fputs("''", out);
22120 }else{
22121 sqlite3_fprintf(out, "\\u%04x", c);
 
 
22122 }
22123 z++;
22124 }
22125 if( needUnistr ){
22126 sqlite3_fputs("')", out);
22127 }else{
22128 sqlite3_fputs("'", out);
22129 }
22130 }
22131 setCrlfMode(p);
22132 }
22133
22134 /*
@@ -22073,65 +22139,19 @@
22139 **
22140 ** This is like output_quoted_string() but with the addition of the \r\n
22141 ** escape mechanism.
22142 */
22143 static void output_quoted_escaped_string(ShellState *p, const char *z){
22144 char *zEscaped;
22145 sqlite3_fsetmode(p->out, _O_BINARY);
22146 if( p->eEscMode==SHELL_ESC_OFF ){
22147 zEscaped = sqlite3_mprintf("%Q", z);
 
 
 
22148 }else{
22149 zEscaped = sqlite3_mprintf("%#Q", z);
22150 }
22151 sqlite3_fputs(zEscaped, p->out);
22152 sqlite3_free(zEscaped);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22153 setCrlfMode(p);
22154 }
22155
22156 /*
22157 ** Find earliest of chars within s specified in zAny.
@@ -22276,10 +22296,97 @@
22296 sqlite3_fputs(ace+1, out);
22297 }
22298 }
22299 sqlite3_fputs(zq, out);
22300 }
22301
22302 /*
22303 ** Escape the input string if it is needed and in accordance with
22304 ** eEscMode.
22305 **
22306 ** Escaping is needed if the string contains any control characters
22307 ** other than \t, \n, and \r\n
22308 **
22309 ** If no escaping is needed (the common case) then set *ppFree to NULL
22310 ** and return the original string. If escapingn is needed, write the
22311 ** escaped string into memory obtained from sqlite3_malloc64() or the
22312 ** equivalent, and return the new string and set *ppFree to the new string
22313 ** as well.
22314 **
22315 ** The caller is responsible for freeing *ppFree if it is non-NULL in order
22316 ** to reclaim memory.
22317 */
22318 static const char *escapeOutput(
22319 ShellState *p,
22320 const char *zInX,
22321 char **ppFree
22322 ){
22323 i64 i, j;
22324 i64 nCtrl = 0;
22325 unsigned char *zIn;
22326 unsigned char c;
22327 unsigned char *zOut;
22328
22329
22330 /* No escaping if disabled */
22331 if( p->eEscMode==SHELL_ESC_OFF ){
22332 *ppFree = 0;
22333 return zInX;
22334 }
22335
22336 /* Count the number of control characters in the string. */
22337 zIn = (unsigned char*)zInX;
22338 for(i=0; (c = zIn[i])!=0; i++){
22339 if( c<=0x1f
22340 && c!='\t'
22341 && c!='\n'
22342 && (c!='\r' || zIn[i+1]!='\n')
22343 ){
22344 nCtrl++;
22345 }
22346 }
22347 if( nCtrl==0 ){
22348 *ppFree = 0;
22349 return zInX;
22350 }
22351 if( p->eEscMode==SHELL_ESC_SYMBOL ) nCtrl *= 2;
22352 zOut = sqlite3_malloc64( i + nCtrl + 1 );
22353 shell_check_oom(zOut);
22354 for(i=j=0; (c = zIn[i])!=0; i++){
22355 if( c>0x1f
22356 || c=='\t'
22357 || c=='\n'
22358 || (c=='\r' && zIn[i+1]=='\n')
22359 ){
22360 continue;
22361 }
22362 if( i>0 ){
22363 memcpy(&zOut[j], zIn, i);
22364 j += i;
22365 }
22366 zIn += i+1;
22367 i = -1;
22368 switch( p->eEscMode ){
22369 case SHELL_ESC_SYMBOL:
22370 zOut[j++] = 0xe2;
22371 zOut[j++] = 0x90;
22372 zOut[j++] = 0x80+c;
22373 break;
22374 case SHELL_ESC_ASCII:
22375 zOut[j++] = '^';
22376 zOut[j++] = 0x40+c;
22377 break;
22378 }
22379 }
22380 if( i>0 ){
22381 memcpy(&zOut[j], zIn, i);
22382 j += i;
22383 }
22384 zOut[j] = 0;
22385 *ppFree = (char*)zOut;
22386 return (char*)zOut;
22387 }
22388
22389 /*
22390 ** Output the given string with characters that are special to
22391 ** HTML escaped.
22392 */
@@ -22720,12 +22827,16 @@
22827 int len = strlen30(azCol[i] ? azCol[i] : "");
22828 if( len>w ) w = len;
22829 }
22830 if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
22831 for(i=0; i<nArg; i++){
22832 char *pFree = 0;
22833 const char *pDisplay;
22834 pDisplay = escapeOutput(p, azArg[i] ? azArg[i] : p->nullValue, &pFree);
22835 sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
22836 pDisplay, p->rowSeparator);
22837 if( pFree ) sqlite3_free(pFree);
22838 }
22839 break;
22840 }
22841 case MODE_ScanExp:
22842 case MODE_Explain: {
@@ -22853,19 +22964,27 @@
22964 break;
22965 }
22966 case MODE_List: {
22967 if( p->cnt++==0 && p->showHeader ){
22968 for(i=0; i<nArg; i++){
22969 char *z = azCol[i];
22970 char *pFree;
22971 const char *zOut = escapeOutput(p, z, &pFree);
22972 sqlite3_fprintf(p->out, "%s%s", zOut,
22973 i==nArg-1 ? p->rowSeparator : p->colSeparator);
22974 if( pFree ) sqlite3_free(pFree);
22975 }
22976 }
22977 if( azArg==0 ) break;
22978 for(i=0; i<nArg; i++){
22979 char *z = azArg[i];
22980 char *pFree;
22981 const char *zOut;
22982 if( z==0 ) z = p->nullValue;
22983 zOut = escapeOutput(p, z, &pFree);
22984 sqlite3_fputs(zOut, p->out);
22985 if( pFree ) sqlite3_free(pFree);
22986 sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
22987 }
22988 break;
22989 }
22990 case MODE_Www:
@@ -23980,10 +24099,11 @@
24099 ** from malloc()) of that first line, which caller should free sometime.
24100 ** Write anything to display on the next line into *pzTail. If this is
24101 ** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
24102 */
24103 static char *translateForDisplayAndDup(
24104 ShellState *p, /* To access current settings */
24105 const unsigned char *z, /* Input text to be transformed */
24106 const unsigned char **pzTail, /* OUT: Tail of the input for next line */
24107 int mxWidth, /* Max width. 0 means no limit */
24108 u8 bWordWrap /* If true, avoid breaking mid-word */
24109 ){
@@ -24014,19 +24134,22 @@
24134 n++;
24135 i++;
24136 j++;
24137 continue;
24138 }
24139 if( c==0 || c=='\n' || (c=='\r' && z[i+1]=='\n') ) break;
24140 if( c=='\t' ){
24141 do{
24142 n++;
24143 j++;
24144 }while( (n&7)!=0 && n<mxWidth );
24145 i++;
24146 continue;
24147 }
24148 n++;
24149 j += 3;
24150 i++;
24151 }
24152 if( n>=mxWidth && bWordWrap ){
24153 /* Perhaps try to back up to a better place to break the line */
24154 for(k=i; k>i/2; k--){
24155 if( isspace(z[k-1]) ) break;
@@ -24069,23 +24192,48 @@
24192 if( c>=' ' ){
24193 n++;
24194 zOut[j++] = z[i++];
24195 continue;
24196 }
24197 if( c==0 ) break;
24198 if( z[i]=='\t' ){
24199 do{
24200 n++;
24201 zOut[j++] = ' ';
24202 }while( (n&7)!=0 && n<mxWidth );
24203 i++;
24204 continue;
24205 }
24206 switch( p->eEscMode ){
24207 case SHELL_ESC_SYMBOL:
24208 zOut[j++] = 0xe2;
24209 zOut[j++] = 0x90;
24210 zOut[j++] = 0x80 + c;
24211 break;
24212 case SHELL_ESC_ASCII:
24213 zOut[j++] = '^';
24214 zOut[j++] = 0x40 + c;
24215 break;
24216 case SHELL_ESC_OFF:
24217 zOut[j++] = c;
24218 break;
24219 }
24220 i++;
24221 }
24222 zOut[j] = 0;
24223 return (char*)zOut;
24224 }
24225
24226 /* Return true if the text string z[] contains characters that need
24227 ** unistr() escaping.
24228 */
24229 static int needUnistr(const unsigned char *z){
24230 unsigned char c;
24231 if( z==0 ) return 0;
24232 while( (c = *z)>0x1f || c=='\t' || c=='\n' || (c=='\r' && z[1]=='\n') ){ z++; }
24233 return c!=0;
24234 }
24235
24236 /* Extract the value of the i-th current column for pStmt as an SQL literal
24237 ** value. Memory is obtained from sqlite3_malloc64() and must be freed by
24238 ** the caller.
24239 */
@@ -24097,11 +24245,12 @@
24245 case SQLITE_INTEGER:
24246 case SQLITE_FLOAT: {
24247 return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
24248 }
24249 case SQLITE_TEXT: {
24250 const unsigned char *zText = sqlite3_column_text(pStmt,i);
24251 return sqlite3_mprintf(needUnistr(zText)?"%#Q":"%Q",zText);
24252 }
24253 case SQLITE_BLOB: {
24254 int j;
24255 sqlite3_str *pStr = sqlite3_str_new(0);
24256 const unsigned char *a = sqlite3_column_blob(pStmt,i);
@@ -24189,11 +24338,11 @@
24338 wx = p->cmOpts.iWrap;
24339 }
24340 if( wx<0 ) wx = -wx;
24341 uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
24342 if( uz==0 ) uz = (u8*)"";
24343 azData[i] = translateForDisplayAndDup(p, uz, &zNotUsed, wx, bw);
24344 }
24345 do{
24346 int useNextLine = bNextLine;
24347 bNextLine = 0;
24348 if( (nRow+2)*nColumn >= nAlloc ){
@@ -24213,19 +24362,20 @@
24362 if( wx<0 ) wx = -wx;
24363 if( useNextLine ){
24364 uz = azNextLine[i];
24365 if( uz==0 ) uz = (u8*)zEmpty;
24366 }else if( p->cmOpts.bQuote ){
24367 assert( azQuoted!=0 );
24368 sqlite3_free(azQuoted[i]);
24369 azQuoted[i] = quoted_column(pStmt,i);
24370 uz = (const unsigned char*)azQuoted[i];
24371 }else{
24372 uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
24373 if( uz==0 ) uz = (u8*)zShowNull;
24374 }
24375 azData[nRow*nColumn + i]
24376 = translateForDisplayAndDup(p, uz, &azNextLine[i], wx, bw);
24377 if( azNextLine[i] ){
24378 bNextLine = 1;
24379 abRowDiv[nRow-1] = 0;
24380 bMultiLineRowExists = 1;
24381 }
@@ -25144,11 +25294,11 @@
25294 #if !defined(SQLITE_SHELL_FIDDLE)
25295 ".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout",
25296 #else
25297 ".log on|off Turn logging on or off.",
25298 #endif
25299 ".mode ?MODE? ?OPTIONS? Set output mode",
25300 " MODE is one of:",
25301 " ascii Columns/rows delimited by 0x1F and 0x1E",
25302 " box Tables using unicode box-drawing characters",
25303 " csv Comma-separated values",
25304 " column Output in columns. (See .width)",
@@ -25162,10 +25312,11 @@
25312 " quote Escape answers as for SQL",
25313 " table ASCII-art table",
25314 " tabs Tab-separated values",
25315 " tcl TCL list elements",
25316 " OPTIONS: (for columnar modes or insert mode):",
25317 " --escape T ctrl-char escape; T is one of: symbol, ascii, off",
25318 " --wrap N Wrap output lines to no longer than N characters",
25319 " --wordwrap B Wrap or not at word boundaries per B (on/off)",
25320 " --ww Shorthand for \"--wordwrap 1\"",
25321 " --quote Quote output text as SQL literals",
25322 " --noquote Do not quote output text",
@@ -27460,11 +27611,11 @@
27611 case AR_SWITCH_VERBOSE:
27612 pAr->bVerbose = 1;
27613 break;
27614 case AR_SWITCH_APPEND:
27615 pAr->bAppend = 1;
27616 deliberate_fall_through; /* FALLTHRU */
27617 case AR_SWITCH_FILE:
27618 pAr->zFile = zArg;
27619 break;
27620 case AR_SWITCH_DIRECTORY:
27621 pAr->zDir = zArg;
@@ -28848,10 +28999,13 @@
28999 if( c=='d' && n>=3 && cli_strncmp(azArg[0], "dbconfig", n)==0 ){
29000 static const struct DbConfigChoices {
29001 const char *zName;
29002 int op;
29003 } aDbConfig[] = {
29004 { "attach_create", SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE },
29005 { "attach_write", SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE },
29006 { "comments", SQLITE_DBCONFIG_ENABLE_COMMENTS },
29007 { "defensive", SQLITE_DBCONFIG_DEFENSIVE },
29008 { "dqs_ddl", SQLITE_DBCONFIG_DQS_DDL },
29009 { "dqs_dml", SQLITE_DBCONFIG_DQS_DML },
29010 { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY },
29011 { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG },
@@ -29899,28 +30053,56 @@
30053
30054 if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
30055 const char *zMode = 0;
30056 const char *zTabname = 0;
30057 int i, n2;
30058 int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */
30059 ColModeOpts cmOpts = ColModeOpts_default;
30060 for(i=1; i<nArg; i++){
30061 const char *z = azArg[i];
30062 if( optionMatch(z,"wrap") && i+1<nArg ){
30063 cmOpts.iWrap = integerValue(azArg[++i]);
30064 chng |= 1;
30065 }else if( optionMatch(z,"ww") ){
30066 cmOpts.bWordWrap = 1;
30067 chng |= 1;
30068 }else if( optionMatch(z,"wordwrap") && i+1<nArg ){
30069 cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
30070 chng |= 1;
30071 }else if( optionMatch(z,"quote") ){
30072 cmOpts.bQuote = 1;
30073 chng |= 1;
30074 }else if( optionMatch(z,"noquote") ){
30075 cmOpts.bQuote = 0;
30076 chng |= 1;
30077 }else if( optionMatch(z,"escape") && i+1<nArg ){
30078 /* See similar code at tag-20250224-1 */
30079 const char *zEsc = azArg[++i];
30080 int k;
30081 for(k=0; k<ArraySize(shell_EscModeNames); k++){
30082 if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
30083 p->eEscMode = k;
30084 chng |= 2;
30085 break;
30086 }
30087 }
30088 if( k>=ArraySize(shell_EscModeNames) ){
30089 sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
30090 " - choices:", zEsc);
30091 for(k=0; k<ArraySize(shell_EscModeNames); k++){
30092 sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
30093 }
30094 sqlite3_fprintf(stderr, "\n");
30095 rc = 1;
30096 goto meta_command_exit;
30097 }
30098 }else if( zMode==0 ){
30099 zMode = z;
30100 /* Apply defaults for qbox pseudo-mode. If that
30101 * overwrites already-set values, user was informed of this.
30102 */
30103 chng |= 1;
30104 if( cli_strcmp(z, "qbox")==0 ){
30105 ColModeOpts cmo = ColModeOpts_default_qbox;
30106 zMode = "box";
30107 cmOpts = cmo;
30108 }
@@ -29927,10 +30109,11 @@
30109 }else if( zTabname==0 ){
30110 zTabname = z;
30111 }else if( z[0]=='-' ){
30112 sqlite3_fprintf(stderr,"unknown option: %s\n", z);
30113 eputz("options:\n"
30114 " --escape MODE\n"
30115 " --noquote\n"
30116 " --quote\n"
30117 " --wordwrap on/off\n"
30118 " --wrap N\n"
30119 " --ww\n");
@@ -29940,24 +30123,33 @@
30123 sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
30124 rc = 1;
30125 goto meta_command_exit;
30126 }
30127 }
30128 if( !chng ){
30129 if( p->mode==MODE_Column
30130 || (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
30131 ){
30132 sqlite3_fprintf(p->out,
30133 "current output mode: %s --wrap %d --wordwrap %s "
30134 "--%squote --escape %s\n",
30135 modeDescr[p->mode], p->cmOpts.iWrap,
30136 p->cmOpts.bWordWrap ? "on" : "off",
30137 p->cmOpts.bQuote ? "" : "no",
30138 shell_EscModeNames[p->eEscMode]
30139 );
30140 }else{
30141 sqlite3_fprintf(p->out,
30142 "current output mode: %s --escape %s\n",
30143 modeDescr[p->mode],
30144 shell_EscModeNames[p->eEscMode]
30145 );
30146 }
30147 }
30148 if( zMode==0 ){
30149 zMode = modeDescr[p->mode];
30150 if( (chng&1)==0 ) cmOpts = p->cmOpts;
30151 }
30152 n2 = strlen30(zMode);
30153 if( cli_strncmp(zMode,"lines",n2)==0 ){
30154 p->mode = MODE_Line;
30155 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
@@ -29986,10 +30178,15 @@
30178 p->mode = MODE_List;
30179 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
30180 }else if( cli_strncmp(zMode,"insert",n2)==0 ){
30181 p->mode = MODE_Insert;
30182 set_table_name(p, zTabname ? zTabname : "table");
30183 if( p->eEscMode==SHELL_ESC_OFF ){
30184 ShellSetFlag(p, SHFLG_Newlines);
30185 }else{
30186 ShellClearFlag(p, SHFLG_Newlines);
30187 }
30188 }else if( cli_strncmp(zMode,"quote",n2)==0 ){
30189 p->mode = MODE_Quote;
30190 sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
30191 sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
30192 }else if( cli_strncmp(zMode,"ascii",n2)==0 ){
@@ -30202,10 +30399,11 @@
30399 }
30400 }
30401 if( zFile==0 ){
30402 zFile = sqlite3_mprintf("stdout");
30403 }
30404 shell_check_oom(zFile);
30405 if( bOnce ){
30406 p->outCount = 2;
30407 }else{
30408 p->outCount = 0;
30409 }
@@ -30244,10 +30442,11 @@
30442 rc = 1;
30443 output_redir(p, stdout);
30444 #else
30445 FILE *pfPipe = sqlite3_popen(zFile + 1, "w");
30446 if( pfPipe==0 ){
30447 assert( stderr!=NULL );
30448 sqlite3_fprintf(stderr,"Error: cannot open pipe \"%s\"\n", zFile + 1);
30449 rc = 1;
30450 }else{
30451 output_redir(p, pfPipe);
30452 if( zBom ) sqlite3_fputs(zBom, pfPipe);
@@ -30256,11 +30455,12 @@
30455 #endif
30456 }else{
30457 FILE *pfFile = output_file_open(zFile);
30458 if( pfFile==0 ){
30459 if( cli_strcmp(zFile,"off")!=0 ){
30460 assert( stderr!=NULL );
30461 sqlite3_fprintf(stderr,"Error: cannot write to \"%s\"\n", zFile);
30462 }
30463 rc = 1;
30464 } else {
30465 output_redir(p, pfFile);
30466 if( zBom ) sqlite3_fputs(zBom, pfFile);
@@ -30360,10 +30560,11 @@
30560 sqlite3_finalize(pStmt);
30561 pStmt = 0;
30562 rc = 1;
30563 }
30564 }
30565 bind_prepared_stmt(p, pStmt);
30566 sqlite3_step(pStmt);
30567 sqlite3_finalize(pStmt);
30568 }else
30569
30570 /* .parameter unset NAME
@@ -31594,10 +31795,11 @@
31795 { 0x01000000, 1, "IndexedEXpr" },
31796 { 0x02000000, 1, "Coroutines" },
31797 { 0x04000000, 1, "NullUnusedCols" },
31798 { 0x08000000, 1, "OnePass" },
31799 { 0x10000000, 1, "OrderBySubq" },
31800 { 0x20000000, 1, "StarQuery" },
31801 { 0xffffffff, 0, "All" },
31802 };
31803 unsigned int curOpt;
31804 unsigned int newOpt;
31805 unsigned int m;
@@ -32148,11 +32350,11 @@
32350 goto TermScan;
32351 }
32352 break;
32353 case '[':
32354 cin = ']';
32355 deliberate_fall_through; /* FALLTHRU */
32356 case '`': case '\'': case '"':
32357 cWait = cin;
32358 qss = QSS_HasDark | cWait;
32359 CONTINUE_PROMPT_AWAITC(pst, cin);
32360 goto TermScan;
@@ -32183,11 +32385,11 @@
32385 if(*zLine==cWait){
32386 /* Swallow doubled end-delimiter.*/
32387 ++zLine;
32388 continue;
32389 }
32390 deliberate_fall_through; /* FALLTHRU */
32391 case ']':
32392 CONTINUE_PROMPT_AWAITC(pst, 0);
32393 qss = QSS_SETV(qss, 0);
32394 goto PlainScan;
32395 default: assert(0);
@@ -32701,10 +32903,11 @@
32903 " -csv set output mode to 'csv'\n"
32904 #if !defined(SQLITE_OMIT_DESERIALIZE)
32905 " -deserialize open the database using sqlite3_deserialize()\n"
32906 #endif
32907 " -echo print inputs before execution\n"
32908 " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n"
32909 " -init FILENAME read/process named file\n"
32910 " -[no]header turn headers on or off\n"
32911 #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
32912 " -heap SIZE Size of heap for memsys3 or memsys5\n"
32913 #endif
@@ -32748,11 +32951,11 @@
32951 #ifdef SQLITE_HAVE_ZLIB
32952 " -zip open the file as a ZIP Archive\n"
32953 #endif
32954 ;
32955 static void usage(int showDetail){
32956 sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
32957 "FILENAME is the name of an SQLite database. A new database is created\n"
32958 "if the file does not previously exist. Defaults to :memory:.\n", Argv0);
32959 if( showDetail ){
32960 sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
32961 }else{
@@ -33134,10 +33337,13 @@
33337 data.zNonce = strdup(cmdline_option_value(argc, argv, ++i));
33338 }else if( cli_strcmp(z,"-unsafe-testing")==0 ){
33339 ShellSetFlag(&data,SHFLG_TestingMode);
33340 }else if( cli_strcmp(z,"-safe")==0 ){
33341 /* no-op - catch this on the second pass */
33342 }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
33343 /* skip over the argument */
33344 i++;
33345 }
33346 }
33347 #ifndef SQLITE_SHELL_FIDDLE
33348 if( !bEnableVfstrace ) verify_uninitialized();
33349 #endif
@@ -33233,10 +33439,29 @@
33439 }else if( cli_strcmp(z,"-box")==0 ){
33440 data.mode = MODE_Box;
33441 }else if( cli_strcmp(z,"-csv")==0 ){
33442 data.mode = MODE_Csv;
33443 memcpy(data.colSeparator,",",2);
33444 }else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
33445 /* See similar code at tag-20250224-1 */
33446 const char *zEsc = argv[++i];
33447 int k;
33448 for(k=0; k<ArraySize(shell_EscModeNames); k++){
33449 if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
33450 data.eEscMode = k;
33451 break;
33452 }
33453 }
33454 if( k>=ArraySize(shell_EscModeNames) ){
33455 sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
33456 " - choices:", zEsc);
33457 for(k=0; k<ArraySize(shell_EscModeNames); k++){
33458 sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
33459 }
33460 sqlite3_fprintf(stderr, "\n");
33461 exit(1);
33462 }
33463 #ifdef SQLITE_HAVE_ZLIB
33464 }else if( cli_strcmp(z,"-zip")==0 ){
33465 data.openMode = SHELL_OPEN_ZIPFILE;
33466 #endif
33467 }else if( cli_strcmp(z,"-append")==0 ){
33468
+3942 -2793
--- extsrc/sqlite3.c
+++ extsrc/sqlite3.c
@@ -1,8 +1,8 @@
11
/******************************************************************************
22
** This file is an amalgamation of many separate C source files from SQLite
3
-** version 3.48.0. By combining all the individual C code files into this
3
+** version 3.50.0. By combining all the individual C code files into this
44
** single large file, the entire code can be compiled as a single translation
55
** unit. This allows many compilers to do optimizations that would not be
66
** possible if the files were compiled separately. Performance improvements
77
** of 5% or more are commonly seen when SQLite is compiled as a single
88
** translation unit.
@@ -16,11 +16,11 @@
1616
** if you want a wrapper to interface SQLite with your choice of programming
1717
** language. The code for the "sqlite3" command-line shell is also in a
1818
** separate file. This file contains only code for the core SQLite library.
1919
**
2020
** The content in this amalgamation comes from Fossil check-in
21
-** e6c30ee52c5cdc193804cec63374d558b45e with changes in files:
21
+** e6784af6d50f715338ae3218fc8ba1b89488 with changes in files:
2222
**
2323
**
2424
*/
2525
#ifndef SQLITE_AMALGAMATION
2626
#define SQLITE_CORE 1
@@ -463,13 +463,13 @@
463463
**
464464
** See also: [sqlite3_libversion()],
465465
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
466466
** [sqlite_version()] and [sqlite_source_id()].
467467
*/
468
-#define SQLITE_VERSION "3.48.0"
469
-#define SQLITE_VERSION_NUMBER 3048000
470
-#define SQLITE_SOURCE_ID "2024-12-19 19:02:09 e6c30ee52c5cdc193804cec63374d558b45e4d67fc6bde58771ca78485ca0acf"
468
+#define SQLITE_VERSION "3.50.0"
469
+#define SQLITE_VERSION_NUMBER 3050000
470
+#define SQLITE_SOURCE_ID "2025-02-25 18:10:47 e6784af6d50f715338ae3218fc8ba1b894883c27d797f0b7fd2625cac17d9cd7"
471471
472472
/*
473473
** CAPI3REF: Run-Time Library Version Numbers
474474
** KEYWORDS: sqlite3_version sqlite3_sourceid
475475
**
@@ -1479,10 +1479,16 @@
14791479
** to block for up to M milliseconds before failing when attempting to
14801480
** obtain a file lock using the xLock or xShmLock methods of the VFS.
14811481
** The parameter is a pointer to a 32-bit signed integer that contains
14821482
** the value that M is to be set to. Before returning, the 32-bit signed
14831483
** integer is overwritten with the previous value of M.
1484
+**
1485
+** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]]
1486
+** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the
1487
+** VFS to block when taking a SHARED lock to connect to a wal mode database.
1488
+** This is used to implement the functionality associated with
1489
+** SQLITE_SETLK_BLOCK_ON_CONNECT.
14841490
**
14851491
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
14861492
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
14871493
** a database file. The argument is a pointer to a 32-bit unsigned integer.
14881494
** The "data version" for the pager is written into the pointer. The
@@ -1576,10 +1582,11 @@
15761582
#define SQLITE_FCNTL_CKPT_START 39
15771583
#define SQLITE_FCNTL_EXTERNAL_READER 40
15781584
#define SQLITE_FCNTL_CKSM_FILE 41
15791585
#define SQLITE_FCNTL_RESET_CACHE 42
15801586
#define SQLITE_FCNTL_NULL_IO 43
1587
+#define SQLITE_FCNTL_BLOCK_ON_CONNECT 44
15811588
15821589
/* deprecated names */
15831590
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
15841591
#define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE
15851592
#define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO
@@ -2306,17 +2313,20 @@
23062313
** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will
23072314
** return [SQLITE_ERROR].</dd>
23082315
**
23092316
** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt>
23102317
** <dd> ^(The SQLITE_CONFIG_LOOKASIDE option takes two arguments that determine
2311
-** the default size of lookaside memory on each [database connection].
2318
+** the default size of [lookaside memory] on each [database connection].
23122319
** The first argument is the
2313
-** size of each lookaside buffer slot and the second is the number of
2314
-** slots allocated to each database connection.)^ ^(SQLITE_CONFIG_LOOKASIDE
2315
-** sets the <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE]
2316
-** option to [sqlite3_db_config()] can be used to change the lookaside
2317
-** configuration on individual connections.)^ </dd>
2320
+** size of each lookaside buffer slot ("sz") and the second is the number of
2321
+** slots allocated to each database connection ("cnt").)^
2322
+** ^(SQLITE_CONFIG_LOOKASIDE sets the <i>default</i> lookaside size.
2323
+** The [SQLITE_DBCONFIG_LOOKASIDE] option to [sqlite3_db_config()] can
2324
+** be used to change the lookaside configuration on individual connections.)^
2325
+** The [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to change the
2326
+** default lookaside configuration at compile-time.
2327
+** </dd>
23182328
**
23192329
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
23202330
** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
23212331
** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
23222332
** the interface to a custom page cache implementation.)^
@@ -2528,11 +2538,19 @@
25282538
25292539
/*
25302540
** CAPI3REF: Database Connection Configuration Options
25312541
**
25322542
** These constants are the available integer configuration options that
2533
-** can be passed as the second argument to the [sqlite3_db_config()] interface.
2543
+** can be passed as the second parameter to the [sqlite3_db_config()] interface.
2544
+**
2545
+** The [sqlite3_db_config()] interface is a var-args functions. It takes a
2546
+** variable number of parameters, though always at least two. The number of
2547
+** parameters passed into sqlite3_db_config() depends on which of these
2548
+** constants is given as the second parameter. This documentation page
2549
+** refers to parameters beyond the second as "arguments". Thus, when this
2550
+** page says "the N-th argument" it means "the N-th parameter past the
2551
+** configuration option" or "the (N+2)-th parameter to sqlite3_db_config()".
25342552
**
25352553
** New configuration options may be added in future releases of SQLite.
25362554
** Existing configuration options might be discontinued. Applications
25372555
** should check the return code from [sqlite3_db_config()] to make sure that
25382556
** the call worked. ^The [sqlite3_db_config()] interface will return a
@@ -2540,35 +2558,61 @@
25402558
** is invoked.
25412559
**
25422560
** <dl>
25432561
** [[SQLITE_DBCONFIG_LOOKASIDE]]
25442562
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
2545
-** <dd> ^This option takes three additional arguments that determine the
2546
-** [lookaside memory allocator] configuration for the [database connection].
2547
-** ^The first argument (the third parameter to [sqlite3_db_config()] is a
2563
+** <dd> The SQLITE_DBCONFIG_LOOKASIDE option is used to adjust the
2564
+** configuration of the [lookaside memory allocator] within a database
2565
+** connection.
2566
+** The arguments to the SQLITE_DBCONFIG_LOOKASIDE option are <i>not</i>
2567
+** in the [DBCONFIG arguments|usual format].
2568
+** The SQLITE_DBCONFIG_LOOKASIDE option takes three arguments, not two,
2569
+** so that a call to [sqlite3_db_config()] that uses SQLITE_DBCONFIG_LOOKASIDE
2570
+** should have a total of five parameters.
2571
+** <ol>
2572
+** <li><p>The first argument ("buf") is a
25482573
** pointer to a memory buffer to use for lookaside memory.
2549
-** ^The first argument after the SQLITE_DBCONFIG_LOOKASIDE verb
2550
-** may be NULL in which case SQLite will allocate the
2551
-** lookaside buffer itself using [sqlite3_malloc()]. ^The second argument is the
2552
-** size of each lookaside buffer slot. ^The third argument is the number of
2553
-** slots. The size of the buffer in the first argument must be greater than
2554
-** or equal to the product of the second and third arguments. The buffer
2555
-** must be aligned to an 8-byte boundary. ^If the second argument to
2556
-** SQLITE_DBCONFIG_LOOKASIDE is not a multiple of 8, it is internally
2557
-** rounded down to the next smaller multiple of 8. ^(The lookaside memory
2574
+** The first argument may be NULL in which case SQLite will allocate the
2575
+** lookaside buffer itself using [sqlite3_malloc()].
2576
+** <li><P>The second argument ("sz") is the
2577
+** size of each lookaside buffer slot. Lookaside is disabled if "sz"
2578
+** is less than 8. The "sz" argument should be a multiple of 8 less than
2579
+** 65536. If "sz" does not meet this constraint, it is reduced in size until
2580
+** it does.
2581
+** <li><p>The third argument ("cnt") is the number of slots. Lookaside is disabled
2582
+** if "cnt"is less than 1. The "cnt" value will be reduced, if necessary, so
2583
+** that the product of "sz" and "cnt" does not exceed 2,147,418,112. The "cnt"
2584
+** parameter is usually chosen so that the product of "sz" and "cnt" is less
2585
+** than 1,000,000.
2586
+** </ol>
2587
+** <p>If the "buf" argument is not NULL, then it must
2588
+** point to a memory buffer with a size that is greater than
2589
+** or equal to the product of "sz" and "cnt".
2590
+** The buffer must be aligned to an 8-byte boundary.
2591
+** The lookaside memory
25582592
** configuration for a database connection can only be changed when that
25592593
** connection is not currently using lookaside memory, or in other words
2560
-** when the "current value" returned by
2561
-** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
2594
+** when the value returned by [SQLITE_DBSTATUS_LOOKASIDE_USED] is zero.
25622595
** Any attempt to change the lookaside memory configuration when lookaside
25632596
** memory is in use leaves the configuration unchanged and returns
2564
-** [SQLITE_BUSY].)^</dd>
2597
+** [SQLITE_BUSY].
2598
+** If the "buf" argument is NULL and an attempt
2599
+** to allocate memory based on "sz" and "cnt" fails, then
2600
+** lookaside is silently disabled.
2601
+** <p>
2602
+** The [SQLITE_CONFIG_LOOKASIDE] configuration option can be used to set the
2603
+** default lookaside configuration at initialization. The
2604
+** [-DSQLITE_DEFAULT_LOOKASIDE] option can be used to set the default lookaside
2605
+** configuration at compile-time. Typical values for lookaside are 1200 for
2606
+** "sz" and 40 to 100 for "cnt".
2607
+** </dd>
25652608
**
25662609
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
25672610
** <dt>SQLITE_DBCONFIG_ENABLE_FKEY</dt>
25682611
** <dd> ^This option is used to enable or disable the enforcement of
2569
-** [foreign key constraints]. There should be two additional arguments.
2612
+** [foreign key constraints]. This is the same setting that is
2613
+** enabled or disabled by the [PRAGMA foreign_keys] statement.
25702614
** The first argument is an integer which is 0 to disable FK enforcement,
25712615
** positive to enable FK enforcement or negative to leave FK enforcement
25722616
** unchanged. The second parameter is a pointer to an integer into which
25732617
** is written 0 or 1 to indicate whether FK enforcement is off or on
25742618
** following this call. The second parameter may be a NULL pointer, in
@@ -2586,17 +2630,17 @@
25862630
** which case the trigger setting is not reported back.
25872631
**
25882632
** <p>Originally this option disabled all triggers. ^(However, since
25892633
** SQLite version 3.35.0, TEMP triggers are still allowed even if
25902634
** this option is off. So, in other words, this option now only disables
2591
-** triggers in the main database schema or in the schemas of ATTACH-ed
2635
+** triggers in the main database schema or in the schemas of [ATTACH]-ed
25922636
** databases.)^ </dd>
25932637
**
25942638
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
25952639
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
25962640
** <dd> ^This option is used to enable or disable [CREATE VIEW | views].
2597
-** There should be two additional arguments.
2641
+** There must be two additional arguments.
25982642
** The first argument is an integer which is 0 to disable views,
25992643
** positive to enable views or negative to leave the setting unchanged.
26002644
** The second parameter is a pointer to an integer into which
26012645
** is written 0 or 1 to indicate whether views are disabled or enabled
26022646
** following this call. The second parameter may be a NULL pointer, in
@@ -2611,11 +2655,11 @@
26112655
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
26122656
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
26132657
** <dd> ^This option is used to enable or disable the
26142658
** [fts3_tokenizer()] function which is part of the
26152659
** [FTS3] full-text search engine extension.
2616
-** There should be two additional arguments.
2660
+** There must be two additional arguments.
26172661
** The first argument is an integer which is 0 to disable fts3_tokenizer() or
26182662
** positive to enable fts3_tokenizer() or negative to leave the setting
26192663
** unchanged.
26202664
** The second parameter is a pointer to an integer into which
26212665
** is written 0 or 1 to indicate whether fts3_tokenizer is disabled or enabled
@@ -2626,11 +2670,11 @@
26262670
** <dt>SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION</dt>
26272671
** <dd> ^This option is used to enable or disable the [sqlite3_load_extension()]
26282672
** interface independently of the [load_extension()] SQL function.
26292673
** The [sqlite3_enable_load_extension()] API enables or disables both the
26302674
** C-API [sqlite3_load_extension()] and the SQL function [load_extension()].
2631
-** There should be two additional arguments.
2675
+** There must be two additional arguments.
26322676
** When the first argument to this interface is 1, then only the C-API is
26332677
** enabled and the SQL function remains disabled. If the first argument to
26342678
** this interface is 0, then both the C-API and the SQL function are disabled.
26352679
** If the first argument is -1, then no changes are made to state of either the
26362680
** C-API or the SQL function.
@@ -2640,27 +2684,34 @@
26402684
** be a NULL pointer, in which case the new setting is not reported back.
26412685
** </dd>
26422686
**
26432687
** [[SQLITE_DBCONFIG_MAINDBNAME]] <dt>SQLITE_DBCONFIG_MAINDBNAME</dt>
26442688
** <dd> ^This option is used to change the name of the "main" database
2645
-** schema. ^The sole argument is a pointer to a constant UTF8 string
2646
-** which will become the new schema name in place of "main". ^SQLite
2647
-** does not make a copy of the new main schema name string, so the application
2648
-** must ensure that the argument passed into this DBCONFIG option is unchanged
2649
-** until after the database connection closes.
2689
+** schema. This option does not follow the
2690
+** [DBCONFIG arguments|usual SQLITE_DBCONFIG argument format].
2691
+** This option takes exactly one additional argument so that the
2692
+** [sqlite3_db_config()] call has a total of three parameters. The
2693
+** extra argument must be a pointer to a constant UTF8 string which
2694
+** will become the new schema name in place of "main". ^SQLite does
2695
+** not make a copy of the new main schema name string, so the application
2696
+** must ensure that the argument passed into SQLITE_DBCONFIG MAINDBNAME
2697
+** is unchanged until after the database connection closes.
26502698
** </dd>
26512699
**
26522700
** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
26532701
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
2654
-** <dd> Usually, when a database in wal mode is closed or detached from a
2655
-** database handle, SQLite checks if this will mean that there are now no
2656
-** connections at all to the database. If so, it performs a checkpoint
2657
-** operation before closing the connection. This option may be used to
2658
-** override this behavior. The first parameter passed to this operation
2659
-** is an integer - positive to disable checkpoints-on-close, or zero (the
2660
-** default) to enable them, and negative to leave the setting unchanged.
2661
-** The second parameter is a pointer to an integer
2702
+** <dd> Usually, when a database in [WAL mode] is closed or detached from a
2703
+** database handle, SQLite checks if if there are other connections to the
2704
+** same database, and if there are no other database connection (if the
2705
+** connection being closed is the last open connection to the database),
2706
+** then SQLite performs a [checkpoint] before closing the connection and
2707
+** deletes the WAL file. The SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE option can
2708
+** be used to override that behavior. The first argument passed to this
2709
+** operation (the third parameter to [sqlite3_db_config()]) is an integer
2710
+** which is positive to disable checkpoints-on-close, or zero (the default)
2711
+** to enable them, and negative to leave the setting unchanged.
2712
+** The second argument (the fourth parameter) is a pointer to an integer
26622713
** into which is written 0 or 1 to indicate whether checkpoints-on-close
26632714
** have been disabled - 0 if they are not disabled, 1 if they are.
26642715
** </dd>
26652716
**
26662717
** [[SQLITE_DBCONFIG_ENABLE_QPSG]] <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
@@ -2817,11 +2868,11 @@
28172868
** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
28182869
** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
28192870
** statistics. For statistics to be collected, the flag must be set on
28202871
** the database handle both when the SQL statement is prepared and when it
28212872
** is stepped. The flag is set (collection of statistics is enabled)
2822
-** by default. This option takes two arguments: an integer and a pointer to
2873
+** by default. <p>This option takes two arguments: an integer and a pointer to
28232874
** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
28242875
** leave unchanged the statement scanstatus option. If the second argument
28252876
** is not NULL, then the value of the statement scanstatus setting after
28262877
** processing the first argument is written into the integer that the second
28272878
** argument points to.
@@ -2831,20 +2882,89 @@
28312882
** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
28322883
** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
28332884
** in which tables and indexes are scanned so that the scans start at the end
28342885
** and work toward the beginning rather than starting at the beginning and
28352886
** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
2836
-** same as setting [PRAGMA reverse_unordered_selects]. This option takes
2887
+** same as setting [PRAGMA reverse_unordered_selects]. <p>This option takes
28372888
** two arguments which are an integer and a pointer to an integer. The first
28382889
** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
28392890
** reverse scan order flag, respectively. If the second argument is not NULL,
28402891
** then 0 or 1 is written into the integer that the second argument points to
28412892
** depending on if the reverse scan order flag is set after processing the
28422893
** first argument.
28432894
** </dd>
28442895
**
2896
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]]
2897
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE</dt>
2898
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE option enables or disables
2899
+** the ability of the [ATTACH DATABASE] SQL command to create a new database
2900
+** file if the database filed named in the ATTACH command does not already
2901
+** exist. This ability of ATTACH to create a new database is enabled by
2902
+** default. Applications can disable or reenable the ability for ATTACH to
2903
+** create new database files using this DBCONFIG option.<p>
2904
+** This option takes two arguments which are an integer and a pointer
2905
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
2906
+** leave unchanged the attach-create flag, respectively. If the second
2907
+** argument is not NULL, then 0 or 1 is written into the integer that the
2908
+** second argument points to depending on if the attach-create flag is set
2909
+** after processing the first argument.
2910
+** </dd>
2911
+**
2912
+** [[SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE]]
2913
+** <dt>SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE</dt>
2914
+** <dd>The SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE option enables or disables the
2915
+** ability of the [ATTACH DATABASE] SQL command to open a database for writing.
2916
+** This capability is enabled by default. Applications can disable or
2917
+** reenable this capability using the current DBCONFIG option. If the
2918
+** the this capability is disabled, the [ATTACH] command will still work,
2919
+** but the database will be opened read-only. If this option is disabled,
2920
+** then the ability to create a new database using [ATTACH] is also disabled,
2921
+** regardless of the value of the [SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE]
2922
+** option.<p>
2923
+** This option takes two arguments which are an integer and a pointer
2924
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
2925
+** leave unchanged the ability to ATTACH another database for writing,
2926
+** respectively. If the second argument is not NULL, then 0 or 1 is written
2927
+** into the integer to which the second argument points, depending on whether
2928
+** the ability to ATTACH a read/write database is enabled or disabled
2929
+** after processing the first argument.
2930
+** </dd>
2931
+**
2932
+** [[SQLITE_DBCONFIG_ENABLE_COMMENTS]]
2933
+** <dt>SQLITE_DBCONFIG_ENABLE_COMMENTS</dt>
2934
+** <dd>The SQLITE_DBCONFIG_ENABLE_COMMENTS option enables or disables the
2935
+** ability to include comments in SQL text. Comments are enabled by default.
2936
+** An application can disable or reenable comments in SQL text using this
2937
+** DBCONFIG option.<p>
2938
+** This option takes two arguments which are an integer and a pointer
2939
+** to an integer. The first argument is 1, 0, or -1 to enable, disable, or
2940
+** leave unchanged the ability to use comments in SQL text,
2941
+** respectively. If the second argument is not NULL, then 0 or 1 is written
2942
+** into the integer that the second argument points to depending on if
2943
+** comments are allowed in SQL text after processing the first argument.
2944
+** </dd>
2945
+**
28452946
** </dl>
2947
+**
2948
+** [[DBCONFIG arguments]] <h3>Arguments To SQLITE_DBCONFIG Options</h3>
2949
+**
2950
+** <p>Most of the SQLITE_DBCONFIG options take two arguments, so that the
2951
+** overall call to [sqlite3_db_config()] has a total of four parameters.
2952
+** The first argument (the third parameter to sqlite3_db_config()) is a integer.
2953
+** The second argument is a pointer to an integer. If the first argument is 1,
2954
+** then the option becomes enabled. If the first integer argument is 0, then the
2955
+** option is disabled. If the first argument is -1, then the option setting
2956
+** is unchanged. The second argument, the pointer to an integer, may be NULL.
2957
+** If the second argument is not NULL, then a value of 0 or 1 is written into
2958
+** the integer to which the second argument points, depending on whether the
2959
+** setting is disabled or enabled after applying any changes specified by
2960
+** the first argument.
2961
+**
2962
+** <p>While most SQLITE_DBCONFIG options use the argument format
2963
+** described in the previous paragraph, the [SQLITE_DBCONFIG_MAINDBNAME]
2964
+** and [SQLITE_DBCONFIG_LOOKASIDE] options are different. See the
2965
+** documentation of those exceptional options for details.
28462966
*/
28472967
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
28482968
#define SQLITE_DBCONFIG_LOOKASIDE 1001 /* void* int int */
28492969
#define SQLITE_DBCONFIG_ENABLE_FKEY 1002 /* int int* */
28502970
#define SQLITE_DBCONFIG_ENABLE_TRIGGER 1003 /* int int* */
@@ -2862,11 +2982,14 @@
28622982
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
28632983
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
28642984
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
28652985
#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
28662986
#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
2867
-#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
2987
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_CREATE 1020 /* int int* */
2988
+#define SQLITE_DBCONFIG_ENABLE_ATTACH_WRITE 1021 /* int int* */
2989
+#define SQLITE_DBCONFIG_ENABLE_COMMENTS 1022 /* int int* */
2990
+#define SQLITE_DBCONFIG_MAX 1022 /* Largest DBCONFIG */
28682991
28692992
/*
28702993
** CAPI3REF: Enable Or Disable Extended Result Codes
28712994
** METHOD: sqlite3
28722995
**
@@ -3216,10 +3339,48 @@
32163339
**
32173340
** See also: [PRAGMA busy_timeout]
32183341
*/
32193342
SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms);
32203343
3344
+/*
3345
+** CAPI3REF: Set the Setlk Timeout
3346
+** METHOD: sqlite3
3347
+**
3348
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If
3349
+** the VFS supports blocking locks, it sets the timeout in ms used by
3350
+** eligible locks taken on wal mode databases by the specified database
3351
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
3352
+** not support blocking locks, this function is a no-op.
3353
+**
3354
+** Passing 0 to this function disables blocking locks altogether. Passing
3355
+** -1 to this function requests that the VFS blocks for a long time -
3356
+** indefinitely if possible. The results of passing any other negative value
3357
+** are undefined.
3358
+**
3359
+** Internally, each SQLite database handle store two timeout values - the
3360
+** busy-timeout (used for rollback mode databases, or if the VFS does not
3361
+** support blocking locks) and the setlk-timeout (used for blocking locks
3362
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
3363
+** values, this function sets only the setlk-timeout value. Therefore,
3364
+** to configure separate busy-timeout and setlk-timeout values for a single
3365
+** database handle, call sqlite3_busy_timeout() followed by this function.
3366
+**
3367
+** Whenever the number of connections to a wal mode database falls from
3368
+** 1 to 0, the last connection takes an exclusive lock on the database,
3369
+** then checkpoints and deletes the wal file. While it is doing this, any
3370
+** new connection that tries to read from the database fails with an
3371
+** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is
3372
+** passed to this API, the new connection blocks until the exclusive lock
3373
+** has been released.
3374
+*/
3375
+SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags);
3376
+
3377
+/*
3378
+** CAPI3REF: Flags for sqlite3_setlk_timeout()
3379
+*/
3380
+#define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01
3381
+
32213382
/*
32223383
** CAPI3REF: Convenience Routines For Running Queries
32233384
** METHOD: sqlite3
32243385
**
32253386
** This is a legacy interface that is preserved for backwards compatibility.
@@ -11065,12 +11226,13 @@
1106511226
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
1106611227
1106711228
/*
1106811229
** CAPI3REF: Serialize a database
1106911230
**
11070
-** The sqlite3_serialize(D,S,P,F) interface returns a pointer to memory
11071
-** that is a serialization of the S database on [database connection] D.
11231
+** The sqlite3_serialize(D,S,P,F) interface returns a pointer to
11232
+** memory that is a serialization of the S database on
11233
+** [database connection] D. If S is a NULL pointer, the main database is used.
1107211234
** If P is not a NULL pointer, then the size of the database in bytes
1107311235
** is written into *P.
1107411236
**
1107511237
** For an ordinary on-disk database file, the serialization is just a
1107611238
** copy of the disk file. For an in-memory database or a "TEMP" database,
@@ -12232,23 +12394,10 @@
1223212394
int nB, /* Number of bytes in buffer pB */
1223312395
void *pB, /* Pointer to buffer containing changeset B */
1223412396
int *pnOut, /* OUT: Number of bytes in output changeset */
1223512397
void **ppOut /* OUT: Buffer containing output changeset */
1223612398
);
12237
-
12238
-
12239
-/*
12240
-** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
12241
-*/
12242
-SQLITE_API int sqlite3changeset_upgrade(
12243
- sqlite3 *db,
12244
- const char *zDb,
12245
- int nIn, const void *pIn, /* Input changeset */
12246
- int *pnOut, void **ppOut /* OUT: Inverse of input */
12247
-);
12248
-
12249
-
1225012399
1225112400
/*
1225212401
** CAPI3REF: Changegroup Handle
1225312402
**
1225412403
** A changegroup is an object used to combine two or more
@@ -13993,18 +14142,26 @@
1399314142
** * Terms in the SET clause of an UPDATE statement
1399414143
** * Terms in the result set of a SELECT statement
1399514144
** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement.
1399614145
** * Terms in the VALUES clause of an INSERT statement
1399714146
**
13998
-** The hard upper limit here is 32676. Most database people will
14147
+** The hard upper limit here is 32767. Most database people will
1399914148
** tell you that in a well-normalized database, you usually should
1400014149
** not have more than a dozen or so columns in any table. And if
1400114150
** that is the case, there is no point in having more than a few
1400214151
** dozen values in any of the other situations described above.
14152
+**
14153
+** An index can only have SQLITE_MAX_COLUMN columns from the user
14154
+** point of view, but the underlying b-tree that implements the index
14155
+** might have up to twice as many columns in a WITHOUT ROWID table,
14156
+** since must also store the primary key at the end. Hence the
14157
+** column count for Index is u16 instead of i16.
1400314158
*/
14004
-#ifndef SQLITE_MAX_COLUMN
14159
+#if !defined(SQLITE_MAX_COLUMN)
1400514160
# define SQLITE_MAX_COLUMN 2000
14161
+#elif SQLITE_MAX_COLUMN>32767
14162
+# error SQLITE_MAX_COLUMN may not exceed 32767
1400614163
#endif
1400714164
1400814165
/*
1400914166
** The maximum length of a single SQL statement in bytes.
1401014167
**
@@ -14652,10 +14809,11 @@
1465214809
*/
1465314810
struct HashElem {
1465414811
HashElem *next, *prev; /* Next and previous elements in the table */
1465514812
void *data; /* Data associated with this element */
1465614813
const char *pKey; /* Key associated with this element */
14814
+ unsigned int h; /* hash for pKey */
1465714815
};
1465814816
1465914817
/*
1466014818
** Access routines. To delete, insert a NULL pointer.
1466114819
*/
@@ -14875,11 +15033,12 @@
1487515033
#define TK_ASTERISK 180
1487615034
#define TK_SPAN 181
1487715035
#define TK_ERROR 182
1487815036
#define TK_QNUMBER 183
1487915037
#define TK_SPACE 184
14880
-#define TK_ILLEGAL 185
15038
+#define TK_COMMENT 185
15039
+#define TK_ILLEGAL 186
1488115040
1488215041
/************** End of parse.h ***********************************************/
1488315042
/************** Continuing where we left off in sqliteInt.h ******************/
1488415043
#include <stdio.h>
1488515044
#include <stdlib.h>
@@ -15089,10 +15248,15 @@
1508915248
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
1509015249
typedef INT16_TYPE i16; /* 2-byte signed integer */
1509115250
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
1509215251
typedef INT8_TYPE i8; /* 1-byte signed integer */
1509315252
15253
+/* A bitfield type for use inside of structures. Always follow with :N where
15254
+** N is the number of bits.
15255
+*/
15256
+typedef unsigned bft; /* Bit Field Type */
15257
+
1509415258
/*
1509515259
** SQLITE_MAX_U32 is a u64 constant that is the maximum u64 value
1509615260
** that can be stored in a u32 without loss of data. The value
1509715261
** is 0x00000000ffffffff. But because of quirks of some compilers, we
1509815262
** have to specify the value in the less intuitive manner shown:
@@ -15127,10 +15291,12 @@
1512715291
** Examples:
1512815292
**
1512915293
** 0.5 -> -10 0.1 -> -33 0.0625 -> -40
1513015294
*/
1513115295
typedef INT16_TYPE LogEst;
15296
+#define LOGEST_MIN (-32768)
15297
+#define LOGEST_MAX (32767)
1513215298
1513315299
/*
1513415300
** Set the SQLITE_PTRSIZE macro to the number of bytes in a pointer
1513515301
*/
1513615302
#ifndef SQLITE_PTRSIZE
@@ -15255,10 +15421,18 @@
1525515421
*/
1525615422
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
1525715423
#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
1525815424
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
1525915425
15426
+/*
15427
+** Macro SMXV(n) return the maximum value that can be held in variable n,
15428
+** assuming n is a signed integer type. UMXV(n) is similar for unsigned
15429
+** integer types.
15430
+*/
15431
+#define SMXV(n) ((((i64)1)<<(sizeof(n)-1))-1)
15432
+#define UMXV(n) ((((i64)1)<<(sizeof(n)))-1)
15433
+
1526015434
/*
1526115435
** Round up a number to the next larger multiple of 8. This is used
1526215436
** to force 8-byte alignment on 64-bit architectures.
1526315437
**
1526415438
** ROUND8() always does the rounding, for any argument.
@@ -15397,11 +15571,11 @@
1539715571
** 0x-------F High-level debug messages
1539815572
** 0x----FFF- More detail
1539915573
** 0xFFFF---- Low-level debug messages
1540015574
**
1540115575
** 0x00000001 Code generation
15402
-** 0x00000002 Solver
15576
+** 0x00000002 Solver (Use 0x40000 for less detail)
1540315577
** 0x00000004 Solver costs
1540415578
** 0x00000008 WhereLoop inserts
1540515579
**
1540615580
** 0x00000010 Display sqlite3_index_info xBestIndex calls
1540715581
** 0x00000020 Range an equality scan metrics
@@ -15416,10 +15590,12 @@
1541615590
** 0x00004000 Show all WHERE terms at key points
1541715591
** 0x00008000 Show the full SELECT statement at key places
1541815592
**
1541915593
** 0x00010000 Show more detail when printing WHERE terms
1542015594
** 0x00020000 Show WHERE terms returned from whereScanNext()
15595
+** 0x00040000 Solver overview messages
15596
+** 0x00080000 Star-query heuristic
1542115597
*/
1542215598
1542315599
1542415600
/*
1542515601
** An instance of the following structure is used to store the busy-handler
@@ -16708,10 +16884,11 @@
1670816884
** A signature for a reusable subroutine that materializes the RHS of
1670916885
** an IN operator.
1671016886
*/
1671116887
struct SubrtnSig {
1671216888
int selId; /* SELECT-id for the SELECT statement on the RHS */
16889
+ u8 bComplete; /* True if fully coded and available for reusable */
1671316890
char *zAff; /* Affinity of the overall IN expression */
1671416891
int iTable; /* Ephemeral table generated by the subroutine */
1671516892
int iAddr; /* Subroutine entry address */
1671616893
int regReturn; /* Register used to hold return address */
1671716894
};
@@ -17952,10 +18129,14 @@
1795218129
BusyHandler busyHandler; /* Busy callback */
1795318130
Db aDbStatic[2]; /* Static space for the 2 default backends */
1795418131
Savepoint *pSavepoint; /* List of active savepoints */
1795518132
int nAnalysisLimit; /* Number of index rows to ANALYZE */
1795618133
int busyTimeout; /* Busy handler timeout, in msec */
18134
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
18135
+ int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */
18136
+ int setlkFlags; /* Flags passed to setlk_timeout() */
18137
+#endif
1795718138
int nSavepoint; /* Number of non-transaction savepoints */
1795818139
int nStatement; /* Number of nested statement-transactions */
1795918140
i64 nDeferredCons; /* Net deferred constraints this transaction. */
1796018141
i64 nDeferredImmCons; /* Net deferred immediate constraints */
1796118142
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
@@ -18038,10 +18219,13 @@
1803818219
/* DELETE, or UPDATE and return */
1803918220
/* the count using a callback. */
1804018221
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
1804118222
#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
1804218223
#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
18224
+#define SQLITE_AttachCreate HI(0x00010) /* ATTACH allowed to create new dbs */
18225
+#define SQLITE_AttachWrite HI(0x00020) /* ATTACH allowed to open for write */
18226
+#define SQLITE_Comments HI(0x00040) /* Enable SQL comments */
1804318227
1804418228
/* Flags used only if debugging */
1804518229
#ifdef SQLITE_DEBUG
1804618230
#define SQLITE_SqlTrace HI(0x0100000) /* Debug print SQL as it executes */
1804718231
#define SQLITE_VdbeListing HI(0x0200000) /* Debug listings of VDBE progs */
@@ -18097,10 +18281,11 @@
1809718281
#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
1809818282
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
1809918283
#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
1810018284
#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
1810118285
#define SQLITE_OrderBySubq 0x10000000 /* ORDER BY in subquery helps outer */
18286
+#define SQLITE_StarQuery 0x20000000 /* Heurists for star queries */
1810218287
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
1810318288
1810418289
/*
1810518290
** Macros for testing whether or not optimizations are enabled or disabled.
1810618291
*/
@@ -18626,10 +18811,11 @@
1862618811
VTable *p; /* List of VTable objects. */
1862718812
} vtab;
1862818813
} u;
1862918814
Trigger *pTrigger; /* List of triggers on this object */
1863018815
Schema *pSchema; /* Schema that contains this table */
18816
+ u8 aHx[16]; /* Column aHt[K%sizeof(aHt)] might have hash K */
1863118817
};
1863218818
1863318819
/*
1863418820
** Allowed values for Table.tabFlags.
1863518821
**
@@ -18945,11 +19131,11 @@
1894519131
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
1894619132
ExprList *aColExpr; /* Column expressions */
1894719133
Pgno tnum; /* DB Page containing root of this index */
1894819134
LogEst szIdxRow; /* Estimated average row size in bytes */
1894919135
u16 nKeyCol; /* Number of columns forming the key */
18950
- u16 nColumn; /* Number of columns stored in the index */
19136
+ u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */
1895119137
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
1895219138
unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */
1895319139
unsigned bUnordered:1; /* Use this index for == or IN queries only */
1895419140
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
1895519141
unsigned isResized:1; /* True if resizeIndexObject() has been called */
@@ -19283,14 +19469,14 @@
1928319469
#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
1928419470
1928519471
/* Macros can be used to test, set, or clear bits in the
1928619472
** Expr.flags field.
1928719473
*/
19288
-#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
19289
-#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
19290
-#define ExprSetProperty(E,P) (E)->flags|=(P)
19291
-#define ExprClearProperty(E,P) (E)->flags&=~(P)
19474
+#define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0)
19475
+#define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P))
19476
+#define ExprSetProperty(E,P) (E)->flags|=(u32)(P)
19477
+#define ExprClearProperty(E,P) (E)->flags&=~(u32)(P)
1929219478
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
1929319479
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
1929419480
#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
1929519481
1929619482
/* Macros used to ensure that the correct members of unions are accessed
@@ -19426,17 +19612,12 @@
1942619612
**
1942719613
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
1942819614
*/
1942919615
struct IdList {
1943019616
int nId; /* Number of identifiers on the list */
19431
- u8 eU4; /* Which element of a.u4 is valid */
1943219617
struct IdList_item {
1943319618
char *zName; /* Name of the identifier */
19434
- union {
19435
- int idx; /* Index in some Table.aCol[] of a column named zName */
19436
- Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
19437
- } u4;
1943819619
} a[1];
1943919620
};
1944019621
1944119622
/*
1944219623
** Allowed values for IdList.eType, which determines which value of the a.u4
@@ -20028,29 +20209,36 @@
2002820209
struct Parse {
2002920210
sqlite3 *db; /* The main database structure */
2003020211
char *zErrMsg; /* An error message */
2003120212
Vdbe *pVdbe; /* An engine for executing database bytecode */
2003220213
int rc; /* Return code from execution */
20033
- u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
20034
- u8 checkSchema; /* Causes schema cookie check after an error */
20214
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
2003520215
u8 nested; /* Number of nested calls to the parser/code generator */
2003620216
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
2003720217
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
2003820218
u8 mayAbort; /* True if statement may throw an ABORT exception */
2003920219
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
20040
- u8 okConstFactor; /* OK to factor out constants */
2004120220
u8 disableLookaside; /* Number of times lookaside has been disabled */
2004220221
u8 prepFlags; /* SQLITE_PREPARE_* flags */
2004320222
u8 withinRJSubrtn; /* Nesting level for RIGHT JOIN body subroutines */
20044
- u8 bHasWith; /* True if statement contains WITH */
2004520223
u8 mSubrtnSig; /* mini Bloom filter on available SubrtnSig.selId */
20224
+ u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
20225
+ u8 bReturning; /* Coding a RETURNING trigger */
20226
+ u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
20227
+ u8 disableTriggers; /* True to disable triggers */
2004620228
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
2004720229
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
2004820230
#endif
2004920231
#ifdef SQLITE_DEBUG
2005020232
u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
20233
+ u8 isCreate; /* CREATE TABLE, INDEX, or VIEW (but not TRIGGER)
20234
+ ** and ALTER TABLE ADD COLUMN. */
2005120235
#endif
20236
+ bft colNamesSet :1; /* TRUE after OP_ColumnName has been issued to pVdbe */
20237
+ bft bHasWith :1; /* True if statement contains WITH */
20238
+ bft okConstFactor :1; /* OK to factor out constants */
20239
+ bft checkSchema :1; /* Causes schema cookie check after an error */
2005220240
int nRangeReg; /* Size of the temporary register block */
2005320241
int iRangeReg; /* First register in temporary register block */
2005420242
int nErr; /* Number of errors seen */
2005520243
int nTab; /* Number of previously allocated VDBE cursors */
2005620244
int nMem; /* Number of memory cells used so far */
@@ -20061,16 +20249,13 @@
2006120249
int nLabelAlloc; /* Number of slots in aLabel */
2006220250
int *aLabel; /* Space to hold the labels */
2006320251
ExprList *pConstExpr;/* Constant expressions */
2006420252
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
2006520253
IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
20066
- Token constraintName;/* Name of the constraint currently being parsed */
2006720254
yDbMask writeMask; /* Start a write transaction on these databases */
2006820255
yDbMask cookieMask; /* Bitmask of schema verified databases */
20069
- int regRowid; /* Register holding rowid of CREATE TABLE entry */
20070
- int regRoot; /* Register holding root page number for new objects */
20071
- int nMaxArg; /* Max args passed to user function by sub-program */
20256
+ int nMaxArg; /* Max args to xUpdate and xFilter vtab methods */
2007220257
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
2007320258
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
2007420259
u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
2007520260
#endif
2007620261
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -20080,21 +20265,10 @@
2008020265
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
2008120266
Parse *pToplevel; /* Parse structure for main program (or NULL) */
2008220267
Table *pTriggerTab; /* Table triggers are being coded for */
2008320268
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
2008420269
ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
20085
- union {
20086
- int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
20087
- Returning *pReturning; /* The RETURNING clause */
20088
- } u1;
20089
- u32 oldmask; /* Mask of old.* columns referenced */
20090
- u32 newmask; /* Mask of new.* columns referenced */
20091
- LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
20092
- u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
20093
- u8 bReturning; /* Coding a RETURNING trigger */
20094
- u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
20095
- u8 disableTriggers; /* True to disable triggers */
2009620270
2009720271
/**************************************************************************
2009820272
** Fields above must be initialized to zero. The fields that follow,
2009920273
** down to the beginning of the recursive section, do not need to be
2010020274
** initialized as they will be set before being used. The boundary is
@@ -20102,10 +20276,23 @@
2010220276
**************************************************************************/
2010320277
2010420278
int aTempReg[8]; /* Holding area for temporary registers */
2010520279
Parse *pOuterParse; /* Outer Parse object when nested */
2010620280
Token sNameToken; /* Token with unqualified schema object name */
20281
+ u32 oldmask; /* Mask of old.* columns referenced */
20282
+ u32 newmask; /* Mask of new.* columns referenced */
20283
+ union {
20284
+ struct { /* These fields available when isCreate is true */
20285
+ int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
20286
+ int regRowid; /* Register holding rowid of CREATE TABLE entry */
20287
+ int regRoot; /* Register holding root page for new objects */
20288
+ Token constraintName; /* Name of the constraint currently being parsed */
20289
+ } cr;
20290
+ struct { /* These fields available to all other statements */
20291
+ Returning *pReturning; /* The RETURNING clause */
20292
+ } d;
20293
+ } u1;
2010720294
2010820295
/************************************************************************
2010920296
** Above is constant between recursions. Below is reset before and after
2011020297
** each recursion. The boundary between these two regions is determined
2011120298
** using offsetof(Parse,sLastToken) so the sLastToken field must be the
@@ -20119,13 +20306,11 @@
2011920306
u8 eParseMode; /* PARSE_MODE_XXX constant */
2012020307
#ifndef SQLITE_OMIT_VIRTUALTABLE
2012120308
int nVtabLock; /* Number of virtual tables to lock */
2012220309
#endif
2012320310
int nHeight; /* Expression tree height of current sub-select */
20124
-#ifndef SQLITE_OMIT_EXPLAIN
2012520311
int addrExplain; /* Address of current OP_Explain opcode */
20126
-#endif
2012720312
VList *pVList; /* Mapping between variable names and numbers */
2012820313
Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */
2012920314
const char *zTail; /* All SQL text past the last semicolon parsed */
2013020315
Table *pNewTable; /* A table being constructed by CREATE TABLE */
2013120316
Index *pNewIndex; /* An index being constructed by CREATE INDEX.
@@ -21095,11 +21280,11 @@
2109521280
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
2109621281
SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
2109721282
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
2109821283
SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int);
2109921284
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
21100
-SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16);
21285
+SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int);
2110121286
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
2110221287
# define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */
2110321288
# define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */
2110421289
#else
2110521290
SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table*, i16);
@@ -21193,11 +21378,11 @@
2119321378
SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*);
2119421379
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
2119521380
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
2119621381
SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
2119721382
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
21198
-SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
21383
+SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**);
2119921384
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
2120021385
Expr*, int, int, u8);
2120121386
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
2120221387
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
2120321388
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
@@ -21329,11 +21514,12 @@
2132921514
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*);
2133021515
SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int);
2133121516
SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
2133221517
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
2133321518
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
21334
-SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
21519
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int);
21520
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32);
2133521521
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
2133621522
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
2133721523
SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void);
2133821524
SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
2133921525
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
@@ -22429,10 +22615,13 @@
2242922615
#ifdef SQLITE_ENABLE_RTREE
2243022616
"ENABLE_RTREE",
2243122617
#endif
2243222618
#ifdef SQLITE_ENABLE_SESSION
2243322619
"ENABLE_SESSION",
22620
+#endif
22621
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
22622
+ "ENABLE_SETLK_TIMEOUT",
2243422623
#endif
2243522624
#ifdef SQLITE_ENABLE_SNAPSHOT
2243622625
"ENABLE_SNAPSHOT",
2243722626
#endif
2243822627
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
@@ -23579,10 +23768,11 @@
2357923768
char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
2358023769
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
2358123770
#ifdef SQLITE_DEBUG
2358223771
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
2358323772
u16 mScopyFlags; /* flags value immediately after the shallow copy */
23773
+ u8 bScopy; /* The pScopyFrom of some other Mem *might* point here */
2358423774
#endif
2358523775
};
2358623776
2358723777
/*
2358823778
** Size of struct Mem not including the Mem.zMalloc member or anything that
@@ -23732,14 +23922,10 @@
2373223922
u8 skipFlag; /* Skip accumulator loading if true */
2373323923
u16 argc; /* Number of arguments */
2373423924
sqlite3_value *argv[1]; /* Argument set */
2373523925
};
2373623926
23737
-/* A bitfield type for use inside of structures. Always follow with :N where
23738
-** N is the number of bits.
23739
-*/
23740
-typedef unsigned bft; /* Bit Field Type */
2374123927
2374223928
/* The ScanStatus object holds a single value for the
2374323929
** sqlite3_stmt_scanstatus() interface.
2374423930
**
2374523931
** aAddrRange[]:
@@ -23796,11 +23982,11 @@
2379623982
i64 iCurrentTime; /* Value of julianday('now') for this statement */
2379723983
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
2379823984
i64 nStmtDefCons; /* Number of def. constraints when stmt started */
2379923985
i64 nStmtDefImmCons; /* Number of def. imm constraints when stmt started */
2380023986
Mem *aMem; /* The memory locations */
23801
- Mem **apArg; /* Arguments to currently executing user function */
23987
+ Mem **apArg; /* Arguments xUpdate and xFilter vtab methods */
2380223988
VdbeCursor **apCsr; /* One element of this array for each open cursor */
2380323989
Mem *aVar; /* Values for the OP_Variable opcode. */
2380423990
2380523991
/* When allocating a new Vdbe object, all of the fields below should be
2380623992
** initialized to zero or NULL */
@@ -23816,10 +24002,11 @@
2381624002
i64 startTime; /* Time when query started - used for profiling */
2381724003
#endif
2381824004
#ifdef SQLITE_DEBUG
2381924005
int rcApp; /* errcode set by sqlite3_result_error_code() */
2382024006
u32 nWrite; /* Number of write operations that have occurred */
24007
+ int napArg; /* Size of the apArg[] array */
2382124008
#endif
2382224009
u16 nResColumn; /* Number of columns in one row of the result set */
2382324010
u16 nResAlloc; /* Column slots allocated to aColName[] */
2382424011
u8 errorAction; /* Recovery action to do in case of an error */
2382524012
u8 minWriteFileFormat; /* Minimum file format for writable database files */
@@ -24246,12 +24433,13 @@
2424624433
u32 nFree = countLookasideSlots(db->lookaside.pFree);
2424724434
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
2424824435
nInit += countLookasideSlots(db->lookaside.pSmallInit);
2424924436
nFree += countLookasideSlots(db->lookaside.pSmallFree);
2425024437
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
24251
- if( pHighwater ) *pHighwater = db->lookaside.nSlot - nInit;
24252
- return db->lookaside.nSlot - (nInit+nFree);
24438
+ assert( db->lookaside.nSlot >= nInit+nFree );
24439
+ if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit);
24440
+ return (int)(db->lookaside.nSlot - (nInit+nFree));
2425324441
}
2425424442
2425524443
/*
2425624444
** Query status information for a single database connection
2425724445
*/
@@ -24300,11 +24488,11 @@
2430024488
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
2430124489
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
2430224490
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
2430324491
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
2430424492
*pCurrent = 0;
24305
- *pHighwater = db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT];
24493
+ *pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT];
2430624494
if( resetFlag ){
2430724495
db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
2430824496
}
2430924497
break;
2431024498
}
@@ -24677,10 +24865,13 @@
2467724865
ms = ms*10.0 + *zDate - '0';
2467824866
rScale *= 10.0;
2467924867
zDate++;
2468024868
}
2468124869
ms /= rScale;
24870
+ /* Truncate to avoid problems with sub-milliseconds
24871
+ ** rounding. https://sqlite.org/forum/forumpost/766a2c9231 */
24872
+ if( ms>0.999 ) ms = 0.999;
2468224873
}
2468324874
}else{
2468424875
s = 0;
2468524876
}
2468624877
p->validJD = 0;
@@ -25884,11 +26075,11 @@
2588426075
sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
2588526076
break;
2588626077
}
2588726078
case 'f': { /* Fractional seconds. (Non-standard) */
2588826079
double s = x.s;
25889
- if( s>59.999 ) s = 59.999;
26080
+ if( NEVER(s>59.999) ) s = 59.999;
2589026081
sqlite3_str_appendf(&sRes, "%06.3f", s);
2589126082
break;
2589226083
}
2589326084
case 'F': {
2589426085
sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
@@ -31412,21 +31603,21 @@
3141231603
#define etSTRING 5 /* Strings. %s */
3141331604
#define etDYNSTRING 6 /* Dynamically allocated strings. %z */
3141431605
#define etPERCENT 7 /* Percent symbol. %% */
3141531606
#define etCHARX 8 /* Characters. %c */
3141631607
/* The rest are extensions, not normally found in printf() */
31417
-#define etSQLESCAPE 9 /* Strings with '\'' doubled. %q */
31418
-#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
31419
- NULL pointers replaced by SQL NULL. %Q */
31420
-#define etTOKEN 11 /* a pointer to a Token structure */
31421
-#define etSRCITEM 12 /* a pointer to a SrcItem */
31422
-#define etPOINTER 13 /* The %p conversion */
31423
-#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
31424
-#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
31425
-#define etDECIMAL 16 /* %d or %u, but not %x, %o */
31426
-
31427
-#define etINVALID 17 /* Any unrecognized conversion type */
31608
+#define etESCAPE_q 9 /* Strings with '\'' doubled. %q */
31609
+#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '',
31610
+ NULL pointers replaced by SQL NULL. %Q */
31611
+#define etTOKEN 11 /* a pointer to a Token structure */
31612
+#define etSRCITEM 12 /* a pointer to a SrcItem */
31613
+#define etPOINTER 13 /* The %p conversion */
31614
+#define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */
31615
+#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
31616
+#define etDECIMAL 16 /* %d or %u, but not %x, %o */
31617
+
31618
+#define etINVALID 17 /* Any unrecognized conversion type */
3142831619
3142931620
3143031621
/*
3143131622
** An "etByte" is an 8-bit unsigned value.
3143231623
*/
@@ -31461,13 +31652,13 @@
3146131652
static const et_info fmtinfo[] = {
3146231653
{ 'd', 10, 1, etDECIMAL, 0, 0 },
3146331654
{ 's', 0, 4, etSTRING, 0, 0 },
3146431655
{ 'g', 0, 1, etGENERIC, 30, 0 },
3146531656
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
31466
- { 'q', 0, 4, etSQLESCAPE, 0, 0 },
31467
- { 'Q', 0, 4, etSQLESCAPE2, 0, 0 },
31468
- { 'w', 0, 4, etSQLESCAPE3, 0, 0 },
31657
+ { 'q', 0, 4, etESCAPE_q, 0, 0 },
31658
+ { 'Q', 0, 4, etESCAPE_Q, 0, 0 },
31659
+ { 'w', 0, 4, etESCAPE_w, 0, 0 },
3146931660
{ 'c', 0, 0, etCHARX, 0, 0 },
3147031661
{ 'o', 8, 0, etRADIX, 0, 2 },
3147131662
{ 'u', 10, 0, etDECIMAL, 0, 0 },
3147231663
{ 'x', 16, 0, etRADIX, 16, 1 },
3147331664
{ 'X', 16, 0, etRADIX, 0, 4 },
@@ -32060,29 +32251,11 @@
3206032251
}else{
3206132252
buf[0] = 0;
3206232253
}
3206332254
}else{
3206432255
unsigned int ch = va_arg(ap,unsigned int);
32065
- if( ch<0x00080 ){
32066
- buf[0] = ch & 0xff;
32067
- length = 1;
32068
- }else if( ch<0x00800 ){
32069
- buf[0] = 0xc0 + (u8)((ch>>6)&0x1f);
32070
- buf[1] = 0x80 + (u8)(ch & 0x3f);
32071
- length = 2;
32072
- }else if( ch<0x10000 ){
32073
- buf[0] = 0xe0 + (u8)((ch>>12)&0x0f);
32074
- buf[1] = 0x80 + (u8)((ch>>6) & 0x3f);
32075
- buf[2] = 0x80 + (u8)(ch & 0x3f);
32076
- length = 3;
32077
- }else{
32078
- buf[0] = 0xf0 + (u8)((ch>>18) & 0x07);
32079
- buf[1] = 0x80 + (u8)((ch>>12) & 0x3f);
32080
- buf[2] = 0x80 + (u8)((ch>>6) & 0x3f);
32081
- buf[3] = 0x80 + (u8)(ch & 0x3f);
32082
- length = 4;
32083
- }
32256
+ length = sqlite3AppendOneUtf8Character(buf, ch);
3208432257
}
3208532258
if( precision>1 ){
3208632259
i64 nPrior = 1;
3208732260
width -= precision-1;
3208832261
if( width>1 && !flag_leftjustify ){
@@ -32158,26 +32331,35 @@
3215832331
/* Adjust width to account for extra bytes in UTF-8 characters */
3215932332
int ii = length - 1;
3216032333
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
3216132334
}
3216232335
break;
32163
- case etSQLESCAPE: /* %q: Escape ' characters */
32164
- case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
32165
- case etSQLESCAPE3: { /* %w: Escape " characters */
32336
+ case etESCAPE_q: /* %q: Escape ' characters */
32337
+ case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */
32338
+ case etESCAPE_w: { /* %w: Escape " characters */
3216632339
i64 i, j, k, n;
32167
- int needQuote, isnull;
32340
+ int needQuote = 0;
3216832341
char ch;
32169
- char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
3217032342
char *escarg;
32343
+ char q;
3217132344
3217232345
if( bArgList ){
3217332346
escarg = getTextArg(pArgList);
3217432347
}else{
3217532348
escarg = va_arg(ap,char*);
3217632349
}
32177
- isnull = escarg==0;
32178
- if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
32350
+ if( escarg==0 ){
32351
+ escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)");
32352
+ }else if( xtype==etESCAPE_Q ){
32353
+ needQuote = 1;
32354
+ }
32355
+ if( xtype==etESCAPE_w ){
32356
+ q = '"';
32357
+ flag_alternateform = 0;
32358
+ }else{
32359
+ q = '\'';
32360
+ }
3217932361
/* For %q, %Q, and %w, the precision is the number of bytes (or
3218032362
** characters if the ! flags is present) to use from the input.
3218132363
** Because of the extra quoting characters inserted, the number
3218232364
** of output characters may be larger than the precision.
3218332365
*/
@@ -32186,26 +32368,77 @@
3218632368
if( ch==q ) n++;
3218732369
if( flag_altform2 && (ch&0xc0)==0xc0 ){
3218832370
while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
3218932371
}
3219032372
}
32191
- needQuote = !isnull && xtype==etSQLESCAPE2;
32373
+ if( flag_alternateform ){
32374
+ /* For %#q, do unistr()-style backslash escapes for
32375
+ ** all control characters, and for backslash itself.
32376
+ ** For %#Q, do the same but only if there is at least
32377
+ ** one control character. */
32378
+ u32 nBack = 0;
32379
+ u32 nCtrl = 0;
32380
+ for(k=0; k<i; k++){
32381
+ if( escarg[k]=='\\' ){
32382
+ nBack++;
32383
+ }else if( escarg[k]<=0x1f ){
32384
+ nCtrl++;
32385
+ }
32386
+ }
32387
+ if( nCtrl || xtype==etESCAPE_q ){
32388
+ n += nBack + 5*nCtrl;
32389
+ if( xtype==etESCAPE_Q ){
32390
+ n += 10;
32391
+ needQuote = 2;
32392
+ }
32393
+ }else{
32394
+ flag_alternateform = 0;
32395
+ }
32396
+ }
3219232397
n += i + 3;
3219332398
if( n>etBUFSIZE ){
3219432399
bufpt = zExtra = printfTempBuf(pAccum, n);
3219532400
if( bufpt==0 ) return;
3219632401
}else{
3219732402
bufpt = buf;
3219832403
}
3219932404
j = 0;
32200
- if( needQuote ) bufpt[j++] = q;
32405
+ if( needQuote ){
32406
+ if( needQuote==2 ){
32407
+ memcpy(&bufpt[j], "unistr('", 8);
32408
+ j += 8;
32409
+ }else{
32410
+ bufpt[j++] = '\'';
32411
+ }
32412
+ }
3220132413
k = i;
32202
- for(i=0; i<k; i++){
32203
- bufpt[j++] = ch = escarg[i];
32204
- if( ch==q ) bufpt[j++] = ch;
32414
+ if( flag_alternateform ){
32415
+ for(i=0; i<k; i++){
32416
+ bufpt[j++] = ch = escarg[i];
32417
+ if( ch==q ){
32418
+ bufpt[j++] = ch;
32419
+ }else if( ch=='\\' ){
32420
+ bufpt[j++] = '\\';
32421
+ }else if( ch<=0x1f ){
32422
+ bufpt[j-1] = '\\';
32423
+ bufpt[j++] = 'u';
32424
+ bufpt[j++] = '0';
32425
+ bufpt[j++] = '0';
32426
+ bufpt[j++] = ch>=0x10 ? '1' : '0';
32427
+ bufpt[j++] = "0123456789abcdef"[ch&0xf];
32428
+ }
32429
+ }
32430
+ }else{
32431
+ for(i=0; i<k; i++){
32432
+ bufpt[j++] = ch = escarg[i];
32433
+ if( ch==q ) bufpt[j++] = ch;
32434
+ }
3220532435
}
32206
- if( needQuote ) bufpt[j++] = q;
32436
+ if( needQuote ){
32437
+ bufpt[j++] = '\'';
32438
+ if( needQuote==2 ) bufpt[j++] = ')';
32439
+ }
3220732440
bufpt[j] = 0;
3220832441
length = j;
3220932442
goto adjust_width_for_utf8;
3221032443
}
3221132444
case etTOKEN: {
@@ -32444,11 +32677,11 @@
3244432677
** pointer if any kind of error was encountered.
3244532678
*/
3244632679
static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
3244732680
char *zText;
3244832681
assert( p->mxAlloc>0 && !isMalloced(p) );
32449
- zText = sqlite3DbMallocRaw(p->db, p->nChar+1 );
32682
+ zText = sqlite3DbMallocRaw(p->db, 1+(u64)p->nChar );
3245032683
if( zText ){
3245132684
memcpy(zText, p->zText, p->nChar+1);
3245232685
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
3245332686
}else{
3245432687
sqlite3StrAccumSetError(p, SQLITE_NOMEM);
@@ -33052,11 +33285,14 @@
3305233285
}
3305333286
if( pItem->fg.fromDDL ){
3305433287
sqlite3_str_appendf(&x, " DDL");
3305533288
}
3305633289
if( pItem->fg.isCte ){
33057
- sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
33290
+ static const char *aMat[] = {",MAT", "", ",NO-MAT"};
33291
+ sqlite3_str_appendf(&x, " CteUse=%d%s",
33292
+ pItem->u2.pCteUse->nUse,
33293
+ aMat[pItem->u2.pCteUse->eM10d]);
3305833294
}
3305933295
if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
3306033296
sqlite3_str_appendf(&x, " isOn");
3306133297
}
3306233298
if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
@@ -33083,13 +33319,10 @@
3308333319
if( pItem->pSTab ){
3308433320
Table *pTab = pItem->pSTab;
3308533321
sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
3308633322
}
3308733323
assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) );
33088
- sqlite3TreeViewPush(&pView, 0);
33089
- sqlite3TreeViewLine(pView, "SUBQUERY");
33090
- sqlite3TreeViewPop(&pView);
3309133324
sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0);
3309233325
}
3309333326
if( pItem->fg.isTabFunc ){
3309433327
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
3309533328
}
@@ -33815,25 +34048,11 @@
3381534048
char *zName = pList->a[i].zName;
3381634049
int moreToFollow = i<pList->nId - 1;
3381734050
if( zName==0 ) zName = "(null)";
3381834051
sqlite3TreeViewPush(&pView, moreToFollow);
3381934052
sqlite3TreeViewLine(pView, 0);
33820
- if( pList->eU4==EU4_NONE ){
33821
- fprintf(stdout, "%s\n", zName);
33822
- }else if( pList->eU4==EU4_IDX ){
33823
- fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
33824
- }else{
33825
- assert( pList->eU4==EU4_EXPR );
33826
- if( pList->a[i].u4.pExpr==0 ){
33827
- fprintf(stdout, "%s (pExpr=NULL)\n", zName);
33828
- }else{
33829
- fprintf(stdout, "%s\n", zName);
33830
- sqlite3TreeViewPush(&pView, i<pList->nId-1);
33831
- sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
33832
- sqlite3TreeViewPop(&pView);
33833
- }
33834
- }
34053
+ fprintf(stdout, "%s\n", zName);
3383534054
sqlite3TreeViewPop(&pView);
3383634055
}
3383734056
}
3383834057
}
3383934058
SQLITE_PRIVATE void sqlite3TreeViewIdList(
@@ -34713,10 +34932,39 @@
3471334932
*zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
3471434933
*zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
3471534934
*zOut++ = (u8)(c&0x00FF); \
3471634935
} \
3471734936
}
34937
+
34938
+/*
34939
+** Write a single UTF8 character whose value is v into the
34940
+** buffer starting at zOut. zOut must be sized to hold at
34941
+** least for bytes. Return the number of bytes needed
34942
+** to encode the new character.
34943
+*/
34944
+SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){
34945
+ if( v<0x00080 ){
34946
+ zOut[0] = (u8)(v & 0xff);
34947
+ return 1;
34948
+ }
34949
+ if( v<0x00800 ){
34950
+ zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f);
34951
+ zOut[1] = 0x80 + (u8)(v & 0x3f);
34952
+ return 2;
34953
+ }
34954
+ if( v<0x10000 ){
34955
+ zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f);
34956
+ zOut[1] = 0x80 + (u8)((v>>6) & 0x3f);
34957
+ zOut[2] = 0x80 + (u8)(v & 0x3f);
34958
+ return 3;
34959
+ }
34960
+ zOut[0] = 0xf0 + (u8)((v>>18) & 0x07);
34961
+ zOut[1] = 0x80 + (u8)((v>>12) & 0x3f);
34962
+ zOut[2] = 0x80 + (u8)((v>>6) & 0x3f);
34963
+ zOut[3] = 0x80 + (u8)(v & 0x3f);
34964
+ return 4;
34965
+}
3471834966
3471934967
/*
3472034968
** Translate a single UTF-8 character. Return the unicode value.
3472134969
**
3472234970
** During translation, assume that the byte that zTerm points
@@ -36310,11 +36558,15 @@
3631036558
}
3631136559
}
3631236560
}
3631336561
p->z = &p->zBuf[i+1];
3631436562
assert( i+p->n < sizeof(p->zBuf) );
36315
- while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
36563
+ assert( p->n>0 );
36564
+ while( p->z[p->n-1]=='0' ){
36565
+ p->n--;
36566
+ assert( p->n>0 );
36567
+ }
3631636568
}
3631736569
3631836570
/*
3631936571
** Try to convert z into an unsigned 32-bit integer. Return true on
3632036572
** success and false if there is an error.
@@ -37096,16 +37348,23 @@
3709637348
/*
3709737349
** The hashing function.
3709837350
*/
3709937351
static unsigned int strHash(const char *z){
3710037352
unsigned int h = 0;
37101
- unsigned char c;
37102
- while( (c = (unsigned char)*z++)!=0 ){ /*OPTIMIZATION-IF-TRUE*/
37353
+ while( z[0] ){ /*OPTIMIZATION-IF-TRUE*/
3710337354
/* Knuth multiplicative hashing. (Sorting & Searching, p. 510).
3710437355
** 0x9e3779b1 is 2654435761 which is the closest prime number to
37105
- ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2. */
37106
- h += sqlite3UpperToLower[c];
37356
+ ** (2**32)*golden_ratio, where golden_ratio = (sqrt(5) - 1)/2.
37357
+ **
37358
+ ** Only bits 0xdf for ASCII and bits 0xbf for EBCDIC each octet are
37359
+ ** hashed since the omitted bits determine the upper/lower case difference.
37360
+ */
37361
+#ifdef SQLITE_EBCDIC
37362
+ h += 0xbf & (unsigned char)*(z++);
37363
+#else
37364
+ h += 0xdf & (unsigned char)*(z++);
37365
+#endif
3710737366
h *= 0x9e3779b1;
3710837367
}
3710937368
return h;
3711037369
}
3711137370
@@ -37174,13 +37433,12 @@
3717437433
sqlite3_free(pH->ht);
3717537434
pH->ht = new_ht;
3717637435
pH->htsize = new_size = sqlite3MallocSize(new_ht)/sizeof(struct _ht);
3717737436
memset(new_ht, 0, new_size*sizeof(struct _ht));
3717837437
for(elem=pH->first, pH->first=0; elem; elem = next_elem){
37179
- unsigned int h = strHash(elem->pKey) % new_size;
3718037438
next_elem = elem->next;
37181
- insertElement(pH, &new_ht[h], elem);
37439
+ insertElement(pH, &new_ht[elem->h % new_size], elem);
3718237440
}
3718337441
return 1;
3718437442
}
3718537443
3718637444
/* This function (for internal use only) locates an element in an
@@ -37194,27 +37452,26 @@
3719437452
unsigned int *pHash /* Write the hash value here */
3719537453
){
3719637454
HashElem *elem; /* Used to loop thru the element list */
3719737455
unsigned int count; /* Number of elements left to test */
3719837456
unsigned int h; /* The computed hash */
37199
- static HashElem nullElement = { 0, 0, 0, 0 };
37457
+ static HashElem nullElement = { 0, 0, 0, 0, 0 };
3720037458
37459
+ h = strHash(pKey);
3720137460
if( pH->ht ){ /*OPTIMIZATION-IF-TRUE*/
3720237461
struct _ht *pEntry;
37203
- h = strHash(pKey) % pH->htsize;
37204
- pEntry = &pH->ht[h];
37462
+ pEntry = &pH->ht[h % pH->htsize];
3720537463
elem = pEntry->chain;
3720637464
count = pEntry->count;
3720737465
}else{
37208
- h = 0;
3720937466
elem = pH->first;
3721037467
count = pH->count;
3721137468
}
3721237469
if( pHash ) *pHash = h;
3721337470
while( count ){
3721437471
assert( elem!=0 );
37215
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
37472
+ if( h==elem->h && sqlite3StrICmp(elem->pKey,pKey)==0 ){
3721637473
return elem;
3721737474
}
3721837475
elem = elem->next;
3721937476
count--;
3722037477
}
@@ -37222,14 +37479,13 @@
3722237479
}
3722337480
3722437481
/* Remove a single entry from the hash table given a pointer to that
3722537482
** element and a hash on the element's key.
3722637483
*/
37227
-static void removeElementGivenHash(
37484
+static void removeElement(
3722837485
Hash *pH, /* The pH containing "elem" */
37229
- HashElem* elem, /* The element to be removed from the pH */
37230
- unsigned int h /* Hash value for the element */
37486
+ HashElem *elem /* The element to be removed from the pH */
3723137487
){
3723237488
struct _ht *pEntry;
3723337489
if( elem->prev ){
3723437490
elem->prev->next = elem->next;
3723537491
}else{
@@ -37237,11 +37493,11 @@
3723737493
}
3723837494
if( elem->next ){
3723937495
elem->next->prev = elem->prev;
3724037496
}
3724137497
if( pH->ht ){
37242
- pEntry = &pH->ht[h];
37498
+ pEntry = &pH->ht[elem->h % pH->htsize];
3724337499
if( pEntry->chain==elem ){
3724437500
pEntry->chain = elem->next;
3724537501
}
3724637502
assert( pEntry->count>0 );
3724737503
pEntry->count--;
@@ -37288,11 +37544,11 @@
3728837544
assert( pKey!=0 );
3728937545
elem = findElementWithHash(pH,pKey,&h);
3729037546
if( elem->data ){
3729137547
void *old_data = elem->data;
3729237548
if( data==0 ){
37293
- removeElementGivenHash(pH,elem,h);
37549
+ removeElement(pH,elem);
3729437550
}else{
3729537551
elem->data = data;
3729637552
elem->pKey = pKey;
3729737553
}
3729837554
return old_data;
@@ -37299,19 +37555,17 @@
3729937555
}
3730037556
if( data==0 ) return 0;
3730137557
new_elem = (HashElem*)sqlite3Malloc( sizeof(HashElem) );
3730237558
if( new_elem==0 ) return data;
3730337559
new_elem->pKey = pKey;
37560
+ new_elem->h = h;
3730437561
new_elem->data = data;
3730537562
pH->count++;
37306
- if( pH->count>=10 && pH->count > 2*pH->htsize ){
37307
- if( rehash(pH, pH->count*2) ){
37308
- assert( pH->htsize>0 );
37309
- h = strHash(pKey) % pH->htsize;
37310
- }
37563
+ if( pH->count>=5 && pH->count > 2*pH->htsize ){
37564
+ rehash(pH, pH->count*3);
3731137565
}
37312
- insertElement(pH, pH->ht ? &pH->ht[h] : 0, new_elem);
37566
+ insertElement(pH, pH->ht ? &pH->ht[new_elem->h % pH->htsize] : 0, new_elem);
3731337567
return 0;
3731437568
}
3731537569
3731637570
/************** End of hash.c ************************************************/
3731737571
/************** Begin file opcodes.c *****************************************/
@@ -38790,10 +39044,11 @@
3879039044
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
3879139045
unsigned fsFlags; /* cached details from statfs() */
3879239046
#endif
3879339047
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
3879439048
unsigned iBusyTimeout; /* Wait this many millisec on locks */
39049
+ int bBlockOnConnect; /* True to block for SHARED locks */
3879539050
#endif
3879639051
#if OS_VXWORKS
3879739052
struct vxworksFileId *pId; /* Unique file ID */
3879839053
#endif
3879939054
#ifdef SQLITE_DEBUG
@@ -40170,11 +40425,11 @@
4017040425
assert( pInode!=0 );
4017140426
assert( sqlite3_mutex_held(pInode->pLockMutex) );
4017240427
if( (pFile->ctrlFlags & (UNIXFILE_EXCL|UNIXFILE_RDONLY))==UNIXFILE_EXCL ){
4017340428
if( pInode->bProcessLock==0 ){
4017440429
struct flock lock;
40175
- assert( pInode->nLock==0 );
40430
+ /* assert( pInode->nLock==0 ); <-- Not true if unix-excl READONLY used */
4017640431
lock.l_whence = SEEK_SET;
4017740432
lock.l_start = SHARED_FIRST;
4017840433
lock.l_len = SHARED_SIZE;
4017940434
lock.l_type = F_WRLCK;
4018040435
rc = osSetPosixAdvisoryLock(pFile->h, &lock, pFile);
@@ -40183,10 +40438,17 @@
4018340438
pInode->nLock++;
4018440439
}else{
4018540440
rc = 0;
4018640441
}
4018740442
}else{
40443
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
40444
+ if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
40445
+ && pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE
40446
+ ){
40447
+ rc = osFcntl(pFile->h, F_SETLKW, pLock);
40448
+ }else
40449
+#endif
4018840450
rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
4018940451
}
4019040452
return rc;
4019140453
}
4019240454
@@ -42544,21 +42806,27 @@
4254442806
return SQLITE_OK;
4254542807
}
4254642808
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
4254742809
case SQLITE_FCNTL_LOCK_TIMEOUT: {
4254842810
int iOld = pFile->iBusyTimeout;
42811
+ int iNew = *(int*)pArg;
4254942812
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
42550
- pFile->iBusyTimeout = *(int*)pArg;
42813
+ pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew;
4255142814
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
4255242815
pFile->iBusyTimeout = !!(*(int*)pArg);
4255342816
#else
4255442817
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
4255542818
#endif
4255642819
*(int*)pArg = iOld;
4255742820
return SQLITE_OK;
4255842821
}
42559
-#endif
42822
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
42823
+ int iNew = *(int*)pArg;
42824
+ pFile->bBlockOnConnect = iNew;
42825
+ return SQLITE_OK;
42826
+ }
42827
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
4256042828
#if SQLITE_MAX_MMAP_SIZE>0
4256142829
case SQLITE_FCNTL_MMAP_SIZE: {
4256242830
i64 newLimit = *(i64*)pArg;
4256342831
int rc = SQLITE_OK;
4256442832
if( newLimit>sqlite3GlobalConfig.mxMmap ){
@@ -43537,11 +43805,11 @@
4353743805
** occur later in the above list than the lock being obtained may be
4353843806
** held.
4353943807
**
4354043808
** It is not permitted to block on the RECOVER lock.
4354143809
*/
43542
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
43810
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
4354343811
{
4354443812
u16 lockMask = (p->exclMask|p->sharedMask);
4354543813
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
4354643814
(ofst!=2) /* not RECOVER */
4354743815
&& (ofst!=1 || lockMask==0 || lockMask==2)
@@ -47067,11 +47335,21 @@
4706747335
HANDLE hMap; /* Handle for accessing memory mapping */
4706847336
void *pMapRegion; /* Area memory mapped */
4706947337
sqlite3_int64 mmapSize; /* Size of mapped region */
4707047338
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
4707147339
#endif
47340
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
47341
+ DWORD iBusyTimeout; /* Wait this many millisec on locks */
47342
+ int bBlockOnConnect;
47343
+#endif
4707247344
};
47345
+
47346
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
47347
+# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout
47348
+#else
47349
+# define winFileBusyTimeout(pDbFd) 0
47350
+#endif
4707347351
4707447352
/*
4707547353
** The winVfsAppData structure is used for the pAppData member for all of the
4707647354
** Win32 VFS variants.
4707747355
*/
@@ -47502,10 +47780,16 @@
4750247780
#endif
4750347781
4750447782
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
4750547783
LPWSTR*))aSyscall[25].pCurrent)
4750647784
47785
+/*
47786
+** For GetLastError(), MSDN says:
47787
+**
47788
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
47789
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
47790
+*/
4750747791
{ "GetLastError", (SYSCALL)GetLastError, 0 },
4750847792
4750947793
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
4751047794
4751147795
#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -47784,15 +48068,17 @@
4778448068
#endif
4778548069
4778648070
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
4778748071
DWORD,DWORD))aSyscall[62].pCurrent)
4778848072
47789
-#if !SQLITE_OS_WINRT
48073
+/*
48074
+** For WaitForSingleObject(), MSDN says:
48075
+**
48076
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
48077
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
48078
+*/
4779048079
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
47791
-#else
47792
- { "WaitForSingleObject", (SYSCALL)0, 0 },
47793
-#endif
4779448080
4779548081
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
4779648082
DWORD))aSyscall[63].pCurrent)
4779748083
4779848084
#if !SQLITE_OS_WINCE
@@ -47935,10 +48221,44 @@
4793548221
#endif
4793648222
4793748223
#define osFlushViewOfFile \
4793848224
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
4793948225
48226
+/*
48227
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent()
48228
+** to implement blocking locks with timeouts. MSDN says:
48229
+**
48230
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
48231
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
48232
+*/
48233
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
48234
+ { "CreateEvent", (SYSCALL)CreateEvent, 0 },
48235
+#else
48236
+ { "CreateEvent", (SYSCALL)0, 0 },
48237
+#endif
48238
+
48239
+#define osCreateEvent ( \
48240
+ (HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \
48241
+ aSyscall[80].pCurrent \
48242
+)
48243
+
48244
+/*
48245
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo()
48246
+** for the case where a timeout expires and a lock request must be
48247
+** cancelled.
48248
+**
48249
+** Minimum supported client: Windows XP [desktop apps | UWP apps]
48250
+** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
48251
+*/
48252
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
48253
+ { "CancelIo", (SYSCALL)CancelIo, 0 },
48254
+#else
48255
+ { "CancelIo", (SYSCALL)0, 0 },
48256
+#endif
48257
+
48258
+#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent)
48259
+
4794048260
}; /* End of the overrideable system calls */
4794148261
4794248262
/*
4794348263
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
4794448264
** "win32" VFSes. Return SQLITE_OK upon successfully updating the
@@ -48233,11 +48553,13 @@
4823348553
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
4823448554
#endif
4823548555
}
4823648556
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
4823748557
#elif SQLITE_TEST
48238
- return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
48558
+ return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2
48559
+ || osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0
48560
+ ;
4823948561
#else
4824048562
/*
4824148563
** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
4824248564
** deprecated are always assumed to be based on the NT kernel.
4824348565
*/
@@ -49319,10 +49641,89 @@
4931949641
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
4932049642
numBytesHigh);
4932149643
}
4932249644
#endif
4932349645
}
49646
+
49647
+/*
49648
+** Lock a region of nByte bytes starting at offset offset of file hFile.
49649
+** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
49650
+** otherwise. If nMs is greater than zero and the lock cannot be obtained
49651
+** immediately, block for that many ms before giving up.
49652
+**
49653
+** This function returns SQLITE_OK if the lock is obtained successfully. If
49654
+** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
49655
+** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
49656
+*/
49657
+static int winHandleLockTimeout(
49658
+ HANDLE hFile,
49659
+ DWORD offset,
49660
+ DWORD nByte,
49661
+ int bExcl,
49662
+ DWORD nMs
49663
+){
49664
+ DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
49665
+ int rc = SQLITE_OK;
49666
+ BOOL ret;
49667
+
49668
+ if( !osIsNT() ){
49669
+ ret = winLockFile(&hFile, flags, offset, 0, nByte, 0);
49670
+ }else{
49671
+ OVERLAPPED ovlp;
49672
+ memset(&ovlp, 0, sizeof(OVERLAPPED));
49673
+ ovlp.Offset = offset;
49674
+
49675
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
49676
+ if( nMs!=0 ){
49677
+ flags &= ~LOCKFILE_FAIL_IMMEDIATELY;
49678
+ }
49679
+ ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL);
49680
+ if( ovlp.hEvent==NULL ){
49681
+ return SQLITE_IOERR_LOCK;
49682
+ }
49683
+#endif
49684
+
49685
+ ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp);
49686
+
49687
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
49688
+ /* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was
49689
+ ** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to
49690
+ ** LockFileEx() may fail because the request is still pending. This can
49691
+ ** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified.
49692
+ **
49693
+ ** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags
49694
+ ** passed to LockFileEx(). In this case, if the operation is pending,
49695
+ ** block indefinitely until it is finished.
49696
+ **
49697
+ ** Otherwise, wait for up to nMs ms for the operation to finish. nMs
49698
+ ** may be set to INFINITE.
49699
+ */
49700
+ if( !ret && GetLastError()==ERROR_IO_PENDING ){
49701
+ DWORD nDelay = (nMs==0 ? INFINITE : nMs);
49702
+ DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay);
49703
+ if( res==WAIT_OBJECT_0 ){
49704
+ ret = TRUE;
49705
+ }else if( res==WAIT_TIMEOUT ){
49706
+ rc = SQLITE_BUSY_TIMEOUT;
49707
+ }else{
49708
+ /* Some other error has occurred */
49709
+ rc = SQLITE_IOERR_LOCK;
49710
+ }
49711
+
49712
+ /* If it is still pending, cancel the LockFileEx() call. */
49713
+ osCancelIo(hFile);
49714
+ }
49715
+
49716
+ osCloseHandle(ovlp.hEvent);
49717
+#endif
49718
+ }
49719
+
49720
+ if( rc==SQLITE_OK && !ret ){
49721
+ rc = SQLITE_BUSY;
49722
+ }
49723
+ return rc;
49724
+}
4932449725
4932549726
/*
4932649727
** Unlock a file region.
4932749728
*/
4932849729
static BOOL winUnlockFile(
@@ -49350,10 +49751,18 @@
4935049751
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
4935149752
numBytesHigh);
4935249753
}
4935349754
#endif
4935449755
}
49756
+
49757
+/*
49758
+** Remove an nByte lock starting at offset iOff from HANDLE h.
49759
+*/
49760
+static int winHandleUnlock(HANDLE h, int iOff, int nByte){
49761
+ BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
49762
+ return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
49763
+}
4935549764
4935649765
/*****************************************************************************
4935749766
** The next group of routines implement the I/O methods specified
4935849767
** by the sqlite3_io_methods object.
4935949768
******************************************************************************/
@@ -49364,69 +49773,73 @@
4936449773
#ifndef INVALID_SET_FILE_POINTER
4936549774
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
4936649775
#endif
4936749776
4936849777
/*
49369
-** Move the current position of the file handle passed as the first
49370
-** argument to offset iOffset within the file. If successful, return 0.
49371
-** Otherwise, set pFile->lastErrno and return non-zero.
49778
+** Seek the file handle h to offset nByte of the file.
49779
+**
49780
+** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
49781
+** error code.
4937249782
*/
49373
-static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
49783
+static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
49784
+ int rc = SQLITE_OK; /* Return value */
49785
+
4937449786
#if !SQLITE_OS_WINRT
4937549787
LONG upperBits; /* Most sig. 32 bits of new offset */
4937649788
LONG lowerBits; /* Least sig. 32 bits of new offset */
4937749789
DWORD dwRet; /* Value returned by SetFilePointer() */
49378
- DWORD lastErrno; /* Value returned by GetLastError() */
49379
-
49380
- OSTRACE(("SEEK file=%p, offset=%lld\n", pFile->h, iOffset));
4938149790
4938249791
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
4938349792
lowerBits = (LONG)(iOffset & 0xffffffff);
49793
+
49794
+ dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN);
4938449795
4938549796
/* API oddity: If successful, SetFilePointer() returns a dword
4938649797
** containing the lower 32-bits of the new file-offset. Or, if it fails,
4938749798
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
4938849799
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
4938949800
** whether an error has actually occurred, it is also necessary to call
49390
- ** GetLastError().
49391
- */
49392
- dwRet = osSetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
49393
-
49394
- if( (dwRet==INVALID_SET_FILE_POINTER
49395
- && ((lastErrno = osGetLastError())!=NO_ERROR)) ){
49396
- pFile->lastErrno = lastErrno;
49397
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
49398
- "winSeekFile", pFile->zPath);
49399
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
49400
- return 1;
49401
- }
49402
-
49403
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
49404
- return 0;
49405
-#else
49406
- /*
49407
- ** Same as above, except that this implementation works for WinRT.
49408
- */
49409
-
49801
+ ** GetLastError(). */
49802
+ if( dwRet==INVALID_SET_FILE_POINTER ){
49803
+ DWORD lastErrno = osGetLastError();
49804
+ if( lastErrno!=NO_ERROR ){
49805
+ rc = SQLITE_IOERR_SEEK;
49806
+ }
49807
+ }
49808
+#else
49809
+ /* This implementation works for WinRT. */
4941049810
LARGE_INTEGER x; /* The new offset */
4941149811
BOOL bRet; /* Value returned by SetFilePointerEx() */
4941249812
4941349813
x.QuadPart = iOffset;
49414
- bRet = osSetFilePointerEx(pFile->h, x, 0, FILE_BEGIN);
49814
+ bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN);
4941549815
4941649816
if(!bRet){
49817
+ rc = SQLITE_IOERR_SEEK;
49818
+ }
49819
+#endif
49820
+
49821
+ OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc)));
49822
+ return rc;
49823
+}
49824
+
49825
+/*
49826
+** Move the current position of the file handle passed as the first
49827
+** argument to offset iOffset within the file. If successful, return 0.
49828
+** Otherwise, set pFile->lastErrno and return non-zero.
49829
+*/
49830
+static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
49831
+ int rc;
49832
+
49833
+ rc = winHandleSeek(pFile->h, iOffset);
49834
+ if( rc!=SQLITE_OK ){
4941749835
pFile->lastErrno = osGetLastError();
49418
- winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
49419
- "winSeekFile", pFile->zPath);
49420
- OSTRACE(("SEEK file=%p, rc=SQLITE_IOERR_SEEK\n", pFile->h));
49421
- return 1;
49422
- }
49423
-
49424
- OSTRACE(("SEEK file=%p, rc=SQLITE_OK\n", pFile->h));
49425
- return 0;
49426
-#endif
49427
-}
49836
+ winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath);
49837
+ }
49838
+ return rc;
49839
+}
49840
+
4942849841
4942949842
#if SQLITE_MAX_MMAP_SIZE>0
4943049843
/* Forward references to VFS helper methods used for memory mapped files */
4943149844
static int winMapfile(winFile*, sqlite3_int64);
4943249845
static int winUnmapfile(winFile*);
@@ -49682,10 +50095,64 @@
4968250095
}
4968350096
OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
4968450097
osGetCurrentProcessId(), pFile, pFile->h));
4968550098
return SQLITE_OK;
4968650099
}
50100
+
50101
+/*
50102
+** Truncate the file opened by handle h to nByte bytes in size.
50103
+*/
50104
+static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){
50105
+ int rc = SQLITE_OK; /* Return code */
50106
+ rc = winHandleSeek(h, nByte);
50107
+ if( rc==SQLITE_OK ){
50108
+ if( 0==osSetEndOfFile(h) ){
50109
+ rc = SQLITE_IOERR_TRUNCATE;
50110
+ }
50111
+ }
50112
+ return rc;
50113
+}
50114
+
50115
+/*
50116
+** Determine the size in bytes of the file opened by the handle passed as
50117
+** the first argument.
50118
+*/
50119
+static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){
50120
+ int rc = SQLITE_OK;
50121
+
50122
+#if SQLITE_OS_WINRT
50123
+ FILE_STANDARD_INFO info;
50124
+ BOOL b;
50125
+ b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info));
50126
+ if( b ){
50127
+ *pnByte = info.EndOfFile.QuadPart;
50128
+ }else{
50129
+ rc = SQLITE_IOERR_FSTAT;
50130
+ }
50131
+#else
50132
+ DWORD upperBits = 0;
50133
+ DWORD lowerBits = 0;
50134
+
50135
+ assert( pnByte );
50136
+ lowerBits = osGetFileSize(h, &upperBits);
50137
+ *pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits;
50138
+ if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){
50139
+ rc = SQLITE_IOERR_FSTAT;
50140
+ }
50141
+#endif
50142
+
50143
+ return rc;
50144
+}
50145
+
50146
+/*
50147
+** Close the handle passed as the only argument.
50148
+*/
50149
+static void winHandleClose(HANDLE h){
50150
+ if( h!=INVALID_HANDLE_VALUE ){
50151
+ osCloseHandle(h);
50152
+ }
50153
+}
4968750154
4968850155
/*
4968950156
** Truncate an open file to a specified size
4969050157
*/
4969150158
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
@@ -49938,31 +50405,32 @@
4993850405
/*
4993950406
** Acquire a reader lock.
4994050407
** Different API routines are called depending on whether or not this
4994150408
** is Win9x or WinNT.
4994250409
*/
49943
-static int winGetReadLock(winFile *pFile){
50410
+static int winGetReadLock(winFile *pFile, int bBlock){
4994450411
int res;
50412
+ DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0);
4994550413
OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
4994650414
if( osIsNT() ){
4994750415
#if SQLITE_OS_WINCE
4994850416
/*
4994950417
** NOTE: Windows CE is handled differently here due its lack of the Win32
4995050418
** API LockFileEx.
4995150419
*/
4995250420
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
4995350421
#else
49954
- res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS, SHARED_FIRST, 0,
50422
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0,
4995550423
SHARED_SIZE, 0);
4995650424
#endif
4995750425
}
4995850426
#ifdef SQLITE_WIN32_HAS_ANSI
4995950427
else{
4996050428
int lk;
4996150429
sqlite3_randomness(sizeof(lk), &lk);
4996250430
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
49963
- res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
50431
+ res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask,
4996450432
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
4996550433
}
4996650434
#endif
4996750435
if( res == 0 ){
4996850436
pFile->lastErrno = osGetLastError();
@@ -50053,50 +50521,66 @@
5005350521
*/
5005450522
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
5005550523
assert( locktype!=PENDING_LOCK );
5005650524
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
5005750525
50058
- /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or
50526
+ /* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or
5005950527
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
5006050528
** the PENDING_LOCK byte is temporary.
5006150529
*/
5006250530
newLocktype = pFile->locktype;
50063
- if( pFile->locktype==NO_LOCK
50064
- || (locktype==EXCLUSIVE_LOCK && pFile->locktype<=RESERVED_LOCK)
50531
+ if( locktype==SHARED_LOCK
50532
+ || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
5006550533
){
5006650534
int cnt = 3;
50067
- while( cnt-->0 && (res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS,
50068
- PENDING_BYTE, 0, 1, 0))==0 ){
50535
+
50536
+ /* Flags for the LockFileEx() call. This should be an exclusive lock if
50537
+ ** this call is to obtain EXCLUSIVE, or a shared lock if this call is to
50538
+ ** obtain SHARED. */
50539
+ int flags = LOCKFILE_FAIL_IMMEDIATELY;
50540
+ if( locktype==EXCLUSIVE_LOCK ){
50541
+ flags |= LOCKFILE_EXCLUSIVE_LOCK;
50542
+ }
50543
+ while( cnt>0 ){
5006950544
/* Try 3 times to get the pending lock. This is needed to work
5007050545
** around problems caused by indexing and/or anti-virus software on
5007150546
** Windows systems.
50547
+ **
5007250548
** If you are using this code as a model for alternative VFSes, do not
50073
- ** copy this retry logic. It is a hack intended for Windows only.
50074
- */
50549
+ ** copy this retry logic. It is a hack intended for Windows only. */
50550
+ res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0);
50551
+ if( res ) break;
50552
+
5007550553
lastErrno = osGetLastError();
5007650554
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
50077
- pFile->h, cnt, res));
50555
+ pFile->h, cnt, res
50556
+ ));
50557
+
5007850558
if( lastErrno==ERROR_INVALID_HANDLE ){
5007950559
pFile->lastErrno = lastErrno;
5008050560
rc = SQLITE_IOERR_LOCK;
5008150561
OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
50082
- pFile->h, cnt, sqlite3ErrName(rc)));
50562
+ pFile->h, cnt, sqlite3ErrName(rc)
50563
+ ));
5008350564
return rc;
5008450565
}
50085
- if( cnt ) sqlite3_win32_sleep(1);
50566
+
50567
+ cnt--;
50568
+ if( cnt>0 ) sqlite3_win32_sleep(1);
5008650569
}
5008750570
gotPendingLock = res;
50088
- if( !res ){
50089
- lastErrno = osGetLastError();
50090
- }
5009150571
}
5009250572
5009350573
/* Acquire a shared lock
5009450574
*/
5009550575
if( locktype==SHARED_LOCK && res ){
5009650576
assert( pFile->locktype==NO_LOCK );
50097
- res = winGetReadLock(pFile);
50577
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
50578
+ res = winGetReadLock(pFile, pFile->bBlockOnConnect);
50579
+#else
50580
+ res = winGetReadLock(pFile, 0);
50581
+#endif
5009850582
if( res ){
5009950583
newLocktype = SHARED_LOCK;
5010050584
}else{
5010150585
lastErrno = osGetLastError();
5010250586
}
@@ -50130,11 +50614,11 @@
5013050614
SHARED_SIZE, 0);
5013150615
if( res ){
5013250616
newLocktype = EXCLUSIVE_LOCK;
5013350617
}else{
5013450618
lastErrno = osGetLastError();
50135
- winGetReadLock(pFile);
50619
+ winGetReadLock(pFile, 0);
5013650620
}
5013750621
}
5013850622
5013950623
/* If we are holding a PENDING lock that ought to be released, then
5014050624
** release it now.
@@ -50210,11 +50694,11 @@
5021050694
OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
5021150695
pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
5021250696
type = pFile->locktype;
5021350697
if( type>=EXCLUSIVE_LOCK ){
5021450698
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
50215
- if( locktype==SHARED_LOCK && !winGetReadLock(pFile) ){
50699
+ if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){
5021650700
/* This should never happen. We should always be able to
5021750701
** reacquire the read lock */
5021850702
rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
5021950703
"winUnlock", pFile->zPath);
5022050704
}
@@ -50420,10 +50904,32 @@
5042050904
}
5042150905
OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
5042250906
return rc;
5042350907
}
5042450908
#endif
50909
+
50910
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
50911
+ case SQLITE_FCNTL_LOCK_TIMEOUT: {
50912
+ int iOld = pFile->iBusyTimeout;
50913
+ int iNew = *(int*)pArg;
50914
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
50915
+ pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew;
50916
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
50917
+ pFile->iBusyTimeout = (DWORD)(!!iNew);
50918
+#else
50919
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
50920
+#endif
50921
+ *(int*)pArg = iOld;
50922
+ return SQLITE_OK;
50923
+ }
50924
+ case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
50925
+ int iNew = *(int*)pArg;
50926
+ pFile->bBlockOnConnect = iNew;
50927
+ return SQLITE_OK;
50928
+ }
50929
+#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
50930
+
5042550931
}
5042650932
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
5042750933
return SQLITE_NOTFOUND;
5042850934
}
5042950935
@@ -50500,36 +51006,39 @@
5050051006
** nRef
5050151007
** pNext
5050251008
**
5050351009
** The following fields are read-only after the object is created:
5050451010
**
50505
-** fid
5050651011
** zFilename
5050751012
**
5050851013
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
5050951014
** winShmMutexHeld() is true when reading or writing any other field
5051051015
** in this structure.
5051151016
**
51017
+** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate
51018
+** the *-shm file if the DMS-locking protocol demands it, and (c) map
51019
+** regions of the *-shm file into memory using MapViewOfFile() or
51020
+** similar. Other locks are taken by individual clients using the
51021
+** winShm.hShm handles.
5051251022
*/
5051351023
struct winShmNode {
5051451024
sqlite3_mutex *mutex; /* Mutex to access this object */
5051551025
char *zFilename; /* Name of the file */
50516
- winFile hFile; /* File handle from winOpen */
51026
+ HANDLE hSharedShm; /* File handle open on zFilename */
5051751027
51028
+ int isUnlocked; /* DMS lock has not yet been obtained */
51029
+ int isReadonly; /* True if read-only */
5051851030
int szRegion; /* Size of shared-memory regions */
5051951031
int nRegion; /* Size of array apRegion */
50520
- u8 isReadonly; /* True if read-only */
50521
- u8 isUnlocked; /* True if no DMS lock held */
5052251032
5052351033
struct ShmRegion {
5052451034
HANDLE hMap; /* File handle from CreateFileMapping */
5052551035
void *pMap;
5052651036
} *aRegion;
5052751037
DWORD lastErrno; /* The Windows errno from the last I/O error */
5052851038
5052951039
int nRef; /* Number of winShm objects pointing to this */
50530
- winShm *pFirst; /* All winShm objects pointing to this */
5053151040
winShmNode *pNext; /* Next in list of all winShmNode objects */
5053251041
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
5053351042
u8 nextShmId; /* Next available winShm.id value */
5053451043
#endif
5053551044
};
@@ -50541,27 +51050,19 @@
5054151050
*/
5054251051
static winShmNode *winShmNodeList = 0;
5054351052
5054451053
/*
5054551054
** Structure used internally by this VFS to record the state of an
50546
-** open shared memory connection.
50547
-**
50548
-** The following fields are initialized when this object is created and
50549
-** are read-only thereafter:
50550
-**
50551
-** winShm.pShmNode
50552
-** winShm.id
50553
-**
50554
-** All other fields are read/write. The winShm.pShmNode->mutex must be held
50555
-** while accessing any read/write fields.
51055
+** open shared memory connection. There is one such structure for each
51056
+** winFile open on a wal mode database.
5055651057
*/
5055751058
struct winShm {
5055851059
winShmNode *pShmNode; /* The underlying winShmNode object */
50559
- winShm *pNext; /* Next winShm with the same winShmNode */
50560
- u8 hasMutex; /* True if holding the winShmNode mutex */
5056151060
u16 sharedMask; /* Mask of shared locks held */
5056251061
u16 exclMask; /* Mask of exclusive locks held */
51062
+ HANDLE hShm; /* File-handle on *-shm file. For locking. */
51063
+ int bReadonly; /* True if hShm is opened read-only */
5056351064
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
5056451065
u8 id; /* Id of this connection with its winShmNode */
5056551066
#endif
5056651067
};
5056751068
@@ -50569,54 +51070,10 @@
5056951070
** Constants used for locking
5057051071
*/
5057151072
#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
5057251073
#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
5057351074
50574
-/*
50575
-** Apply advisory locks for all n bytes beginning at ofst.
50576
-*/
50577
-#define WINSHM_UNLCK 1
50578
-#define WINSHM_RDLCK 2
50579
-#define WINSHM_WRLCK 3
50580
-static int winShmSystemLock(
50581
- winShmNode *pFile, /* Apply locks to this open shared-memory segment */
50582
- int lockType, /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
50583
- int ofst, /* Offset to first byte to be locked/unlocked */
50584
- int nByte /* Number of bytes to lock or unlock */
50585
-){
50586
- int rc = 0; /* Result code form Lock/UnlockFileEx() */
50587
-
50588
- /* Access to the winShmNode object is serialized by the caller */
50589
- assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
50590
-
50591
- OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
50592
- pFile->hFile.h, lockType, ofst, nByte));
50593
-
50594
- /* Release/Acquire the system-level lock */
50595
- if( lockType==WINSHM_UNLCK ){
50596
- rc = winUnlockFile(&pFile->hFile.h, ofst, 0, nByte, 0);
50597
- }else{
50598
- /* Initialize the locking parameters */
50599
- DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY;
50600
- if( lockType == WINSHM_WRLCK ) dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
50601
- rc = winLockFile(&pFile->hFile.h, dwFlags, ofst, 0, nByte, 0);
50602
- }
50603
-
50604
- if( rc!= 0 ){
50605
- rc = SQLITE_OK;
50606
- }else{
50607
- pFile->lastErrno = osGetLastError();
50608
- rc = SQLITE_BUSY;
50609
- }
50610
-
50611
- OSTRACE(("SHM-LOCK file=%p, func=%s, errno=%lu, rc=%s\n",
50612
- pFile->hFile.h, (lockType == WINSHM_UNLCK) ? "winUnlockFile" :
50613
- "winLockFile", pFile->lastErrno, sqlite3ErrName(rc)));
50614
-
50615
- return rc;
50616
-}
50617
-
5061851075
/* Forward references to VFS methods */
5061951076
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
5062051077
static int winDelete(sqlite3_vfs *,const char*,int);
5062151078
5062251079
/*
@@ -50644,15 +51101,11 @@
5064451101
bRc = osCloseHandle(p->aRegion[i].hMap);
5064551102
OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
5064651103
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
5064751104
UNUSED_VARIABLE_VALUE(bRc);
5064851105
}
50649
- if( p->hFile.h!=NULL && p->hFile.h!=INVALID_HANDLE_VALUE ){
50650
- SimulateIOErrorBenign(1);
50651
- winClose((sqlite3_file *)&p->hFile);
50652
- SimulateIOErrorBenign(0);
50653
- }
51106
+ winHandleClose(p->hSharedShm);
5065451107
if( deleteFlag ){
5065551108
SimulateIOErrorBenign(1);
5065651109
sqlite3BeginBenignMalloc();
5065751110
winDelete(pVfs, p->zFilename, 0);
5065851111
sqlite3EndBenignMalloc();
@@ -50666,46 +51119,166 @@
5066651119
}
5066751120
}
5066851121
}
5066951122
5067051123
/*
50671
-** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
50672
-** take it now. Return SQLITE_OK if successful, or an SQLite error
50673
-** code otherwise.
50674
-**
50675
-** If the DMS cannot be locked because this is a readonly_shm=1
50676
-** connection and no other process already holds a lock, return
50677
-** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
51124
+** The DMS lock has not yet been taken on the shm file associated with
51125
+** pShmNode. Take the lock. Truncate the *-shm file if required.
51126
+** Return SQLITE_OK if successful, or an SQLite error code otherwise.
5067851127
*/
50679
-static int winLockSharedMemory(winShmNode *pShmNode){
50680
- int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
51128
+static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
51129
+ HANDLE h = pShmNode->hSharedShm;
51130
+ int rc = SQLITE_OK;
5068151131
51132
+ assert( sqlite3_mutex_held(pShmNode->mutex) );
51133
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0);
5068251134
if( rc==SQLITE_OK ){
51135
+ /* We have an EXCLUSIVE lock on the DMS byte. This means that this
51136
+ ** is the first process to open the file. Truncate it to zero bytes
51137
+ ** in this case. */
5068351138
if( pShmNode->isReadonly ){
50684
- pShmNode->isUnlocked = 1;
50685
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
50686
- return SQLITE_READONLY_CANTINIT;
50687
- }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
50688
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
50689
- return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
50690
- "winLockSharedMemory", pShmNode->zFilename);
50691
- }
50692
- }
50693
-
50694
- if( rc==SQLITE_OK ){
50695
- winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
50696
- }
50697
-
50698
- return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
50699
-}
50700
-
50701
-/*
50702
-** Open the shared-memory area associated with database file pDbFd.
50703
-**
50704
-** When opening a new shared-memory file, if no other instances of that
50705
-** file are currently open, in this process or in other processes, then
50706
-** the file must be truncated to zero length or have its header cleared.
51139
+ rc = SQLITE_READONLY_CANTINIT;
51140
+ }else{
51141
+ rc = winHandleTruncate(h, 0);
51142
+ }
51143
+
51144
+ /* Release the EXCLUSIVE lock acquired above. */
51145
+ winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0);
51146
+ }else if( (rc & 0xFF)==SQLITE_BUSY ){
51147
+ rc = SQLITE_OK;
51148
+ }
51149
+
51150
+ if( rc==SQLITE_OK ){
51151
+ /* Take a SHARED lock on the DMS byte. */
51152
+ rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs);
51153
+ if( rc==SQLITE_OK ){
51154
+ pShmNode->isUnlocked = 0;
51155
+ }
51156
+ }
51157
+
51158
+ return rc;
51159
+}
51160
+
51161
+
51162
+/*
51163
+** Convert a UTF-8 filename into whatever form the underlying
51164
+** operating system wants filenames in. Space to hold the result
51165
+** is obtained from malloc and must be freed by the calling
51166
+** function.
51167
+*/
51168
+static void *winConvertFromUtf8Filename(const char *zFilename){
51169
+ void *zConverted = 0;
51170
+ if( osIsNT() ){
51171
+ zConverted = winUtf8ToUnicode(zFilename);
51172
+ }
51173
+#ifdef SQLITE_WIN32_HAS_ANSI
51174
+ else{
51175
+ zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
51176
+ }
51177
+#endif
51178
+ /* caller will handle out of memory */
51179
+ return zConverted;
51180
+}
51181
+
51182
+/*
51183
+** This function is used to open a handle on a *-shm file.
51184
+**
51185
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
51186
+** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
51187
+*/
51188
+static int winHandleOpen(
51189
+ const char *zUtf8, /* File to open */
51190
+ int *pbReadonly, /* IN/OUT: True for readonly handle */
51191
+ HANDLE *ph /* OUT: New HANDLE for file */
51192
+){
51193
+ int rc = SQLITE_OK;
51194
+ void *zConverted = 0;
51195
+ int bReadonly = *pbReadonly;
51196
+ HANDLE h = INVALID_HANDLE_VALUE;
51197
+
51198
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
51199
+ const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED;
51200
+#else
51201
+ const DWORD flag_overlapped = 0;
51202
+#endif
51203
+
51204
+ /* Convert the filename to the system encoding. */
51205
+ zConverted = winConvertFromUtf8Filename(zUtf8);
51206
+ if( zConverted==0 ){
51207
+ OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8));
51208
+ rc = SQLITE_IOERR_NOMEM_BKPT;
51209
+ goto winopenfile_out;
51210
+ }
51211
+
51212
+ /* Ensure the file we are trying to open is not actually a directory. */
51213
+ if( winIsDir(zConverted) ){
51214
+ OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8));
51215
+ rc = SQLITE_CANTOPEN_ISDIR;
51216
+ goto winopenfile_out;
51217
+ }
51218