Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Merge trunk into the merge-info-html branch. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | merge-info-html |
| Files: | files | file ages | folders |
| SHA3-256: |
1014ffb553117ca4113dcc5071d3389f |
| User & Date: | stephan 2025-03-27 12:42:00.821 |
| Original Comment: | Merge trunk into the merge-info-trunk branch. |
Context
|
2025-03-27
| ||
| 12:42 | Merge trunk into the merge-info-html branch. ... (Leaf check-in: 1014ffb553 user: stephan tags: merge-info-html) | |
|
2025-03-26
| ||
| 22:56 | Updates to the change log. ... (check-in: 0db5c15990 user: drh tags: trunk) | |
|
2025-02-20
| ||
| 14:46 | Bring the merge-info-html branch up to date with trunk, step 2 of 2. ... (check-in: c2b1c2c9fa user: stephan tags: merge-info-html) | |
Changes
Changes to .fossil-settings/crlf-glob.
1 2 3 4 5 | compat/zlib/* setup/fossil.iss test/th1-docs-input.txt test/th1-hooks-input.txt win/buildmsvc.bat | > > | 1 2 3 4 5 6 7 | compat/zlib/* setup/fossil.iss test/th1-docs-input.txt test/th1-hooks-input.txt win/build32.bat win/build64.bat win/buildmsvc.bat |
Changes to .fossil-settings/ignore-glob.
1 2 3 4 5 6 7 8 9 | compat/openssl* compat/tcl* compat/zlib/contrib/ada/* compat/zlib/doc/* fossil fossil.exe win/fossil.exe *shell-see.* *sqlite3-see.* | > | 1 2 3 4 5 6 7 8 9 10 | compat/openssl* compat/tcl* compat/zlib/contrib/ada/* compat/zlib/doc/* fossil fossil.exe win/fossil.exe *shell-see.* *sqlite3-see.* bld |
Makefile.in became a regular file.
| ︙ | ︙ |
Changes to auto.def.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
compile-commands=0 =>
"Check for compile_commands.json support."
}
# Update the minimum required SQLite version number here, and also
# in src/main.c near the sqlite3_libversion_number() call. Take care
# that both places agree!
| | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
compile-commands=0 =>
"Check for compile_commands.json support."
}
# Update the minimum required SQLite version number here, and also
# in src/main.c near the sqlite3_libversion_number() call. Take care
# that both places agree!
define MINIMUM_SQLITE_VERSION "3.49.0"
# This is useful for people wanting Fossil to use an external SQLite library
# to compare the one they have against the minimum required
if {[opt-bool print-minimum-sqlite-version]} {
puts [get-define MINIMUM_SQLITE_VERSION]
exit 0
}
# Space characters have never been allowed in either the source
# tree nor the build directory. But the resulting error messages
# could be confusing. The following checks make the reason for the
# failure clear.
#
|
| ︙ | ︙ | |||
65 66 67 68 69 70 71 |
if {![file exists fossil.1]} {
puts "This appears to be an out-of-tree build."
set outOfTreeBuild 1
}
# sqlite wants these types if possible
cc-with {-includes {stdint.h inttypes.h}} {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
if {![file exists fossil.1]} {
puts "This appears to be an out-of-tree build."
set outOfTreeBuild 1
}
# sqlite wants these types if possible
cc-with {-includes {stdint.h inttypes.h}} {
cc-check-types uint32_t uint16_t int16_t uint8_t
}
# Use pread/pwrite system calls in place of seek + read/write if possible
define USE_PREAD [cc-check-functions pread]
# If we have cscope here, we'll use it in the "tags" target
if {[cc-check-progs cscope]} {
define COLLECT_CSCOPE_DATA "cscope -bR $::autosetup(srcdir)/src/*.\[ch\]"
} else {
define COLLECT_CSCOPE_DATA ""
}
# Find tclsh for the test suite.
#
# We can't use jimsh for this: the test suite uses features of Tcl that
# Jim doesn't support, either statically or due to the way it's built by
# autosetup. For example, Jim supports `file normalize`, but only if
# you build it with HAVE_REALPATH, which won't ever be defined in this
# context because autosetup doesn't try to discover platform-specific
# details like that before it decides to build jimsh0. Besides which,
# autosetup won't build jimsh0 at all if it can find tclsh itself.
# Ironically, this means we may right now be running under either jimsh0
# or a version of tclsh that we find unsuitable below!
cc-check-progs tclsh
set hbtd /usr/local/Cellar/tcl-tk
if {[string equal false [get-define TCLSH]]} {
msg-result "WARNING: 'make test' will not run here."
} else {
set v [exec sh -c "echo 'puts \$tcl_version' | tclsh"]
if {[expr {$v >= 8.6}]} {
msg-result "Found Tclsh version $v in the PATH."
define TCLSH tclsh
} elseif {[file isdirectory $hbtd]} {
# This is a macOS system with the Homebrew version of Tcl/Tk
# installed. Select the newest version. It won't normally be
# in the PATH to avoid shadowing /usr/bin/tclsh, and even if it
# were in the PATH, it's bad practice to put /usr/local/bin (the
# Homebrew default) ahead of /usr/bin, especially given that
# it's user-writeable by default with Homebrew. Thus, we can be
# pretty sure the only way to call it is with an absolute path.
set v [exec ls -tr $hbtd | tail -1]
set path "$hbtd/$v/bin/tclsh"
define TCLSH $path
msg-result "Using Homebrew Tcl/Tk version $path."
} else {
msg-result "WARNING: tclsh $v found; need >= 8.6 for 'make test'."
define TCLSH false ;# force "make test" failure via /usr/bin/false
}
}
define CFLAGS [get-env CFLAGS "-g -Os"]
define EXTRA_CFLAGS "-Wall"
define EXTRA_LDFLAGS ""
define USE_SYSTEM_SQLITE 0
define USE_LINENOISE 0
define USE_MMAN_H 0
define USE_SEE 0
define SQLITE3_ORIGIN 0
# SQLITE3_ORIGIN 0 = src/sqlite3, 1=src/sqlite3-see.c, 2=client-provided
define SQLITE_OPTIONS_EXT ""
# SQLITE_OPTIONS_EXT => build-dependent CFLAGS for sqlite3.c and shell.c
# Maintain the C89/C90-style order of variable declarations before statements.
# Check if the compiler supports the respective warning flag.
if {[cctest -cflags -Wdeclaration-after-statement]} {
define-append EXTRA_CFLAGS -Wdeclaration-after-statement
}
# This procedure is a customized version of "cc-check-function-in-lib",
# that does not modify the LIBS variable. Its use prevents prematurely
# pulling in libraries that will be added later anyhow (e.g. "-ldl").
proc check-function-in-lib {function libs {otherlibs {}}} {
if {[string length $otherlibs]} {
msg-checking "Checking for $function in $libs with $otherlibs..."
} else {
msg-checking "Checking for $function in $libs..."
}
set found 0
cc-with [list -libs $otherlibs] {
if {[cctest_function $function]} {
msg-result "none needed"
define lib_$function ""
incr found
} else {
foreach lib $libs {
cc-with [list -libs -l$lib] {
if {[cctest_function $function]} {
msg-result -l$lib
define lib_$function -l$lib
incr found
break
}
}
}
}
}
if {$found} {
define [feature-define-name $function]
} else {
msg-result "no"
}
return $found
}
if {![opt-bool internal-sqlite]} {
proc find_system_sqlite {} {
# On some systems (slackware), libsqlite3 requires -ldl to link. So
# search for the system SQLite once with -ldl, and once without. If
|
| ︙ | ︙ | |||
217 218 219 220 221 222 223 |
lappend cmdline {*}[get-define LDFLAGS]
lappend cmdline {*}[get-define LIBS]
set sqlite-version [string cat "-D MINIMUM_SQLITE_VERSION=" [get-define MINIMUM_SQLITE_VERSION]]
lappend cmdline {*}[set sqlite-version]
set ok 1
set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
if {$err} {
| | | | | | | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
lappend cmdline {*}[get-define LDFLAGS]
lappend cmdline {*}[get-define LIBS]
set sqlite-version [string cat "-D MINIMUM_SQLITE_VERSION=" [get-define MINIMUM_SQLITE_VERSION]]
lappend cmdline {*}[set sqlite-version]
set ok 1
set err [catch {exec-with-stderr {*}$cmdline} result errinfo]
if {$err} {
configlog "Failed: [join $cmdline]"
if {[string length $result]>0} {configlog $result}
configlog "============"
set ok 0
} elseif {$::autosetup(debug)} {
configlog "Compiled OK: [join $cmdline]"
configlog "============"
}
if {!$ok} {
user-error "unable to compile SQLite compatibility test program"
}
set err [catch {exec-with-stderr ./conftest__} result errinfo]
if {[get-define build] eq [get-define host]} {
set err [catch {exec-with-stderr ./conftest__} result errinfo]
|
| ︙ | ︙ | |||
249 250 251 252 253 254 255 |
return [expr {
[string match *mingw* [get-define host]] &&
![file exists "/dev/null"]
}]
}
if {[is_mingw]} {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > | | | | | | | | | | | | | > | | | | | | | | | | | | | | | | | > > > > > | > > | > | | | | | | | | | | | | > > | | | | | | < < | | | | | | | | | | | | | | | | | | | | | | > | > > > > > > > > > < < | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | > > > > | | > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < | 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 |
return [expr {
[string match *mingw* [get-define host]] &&
![file exists "/dev/null"]
}]
}
if {[is_mingw]} {
define-append EXTRA_CFLAGS -DBROKEN_MINGW_CMDLINE
define-append LIBS -lkernel32 -lws2_32
} else {
#
# NOTE: All platforms except MinGW should use the linenoise
# package. It is currently unsupported on Win32.
#
define USE_LINENOISE 1
}
if {[string match *-solaris* [get-define host]]} {
define-append EXTRA_CFLAGS {-D__EXTENSIONS__}
}
if {[opt-bool fossil-debug]} {
define CFLAGS {-g -O0 -Wall}
define-append CFLAGS -DFOSSIL_DEBUG
msg-result "Debugging support enabled"
}
if {[opt-bool no-opt]} {
define CFLAGS {-g -O0 -Wall}
msg-result "Builting without compiler optimization"
if {[opt-bool fossil-debug]} {
define-append CFLAGS -DFOSSIL_DEBUG
}
}
if {[opt-bool with-mman]} {
define-append EXTRA_CFLAGS -DUSE_MMAN_H
define USE_MMAN_H 1
msg-result "Enabling \"sys/mman.h\" support"
}
if {[opt-bool with-see]} {
define-append EXTRA_CFLAGS -DUSE_SEE
define USE_SEE 1
define SQLITE3_ORIGIN 1
msg-result "Enabling encryption support"
}
if {[opt-bool json]} {
# Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
# is required in the CFLAGS because json*.c
# have #ifdef guards around the whole file without
# reading config.h first.
define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
define FOSSIL_ENABLE_JSON
msg-result "JSON support enabled"
}
if {[opt-bool with-exec-rel-paths]} {
define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_EXEC_REL_PATHS
define FOSSIL_ENABLE_EXEC_REL_PATHS
msg-result "Relative paths in external diff/gdiff enabled"
}
if {[opt-bool with-th1-docs]} {
define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_DOCS
define FOSSIL_ENABLE_TH1_DOCS
msg-result "TH1 embedded documentation support enabled"
}
if {[opt-bool with-th1-hooks]} {
define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_TH1_HOOKS
define FOSSIL_ENABLE_TH1_HOOKS
msg-result "TH1 hooks support enabled"
}
#if {[opt-bool markdown]} {
# # no-op. Markdown is now enabled by default.
# msg-result "Markdown support enabled"
#}
if {[opt-bool static]} {
# XXX: This will not work on all systems.
define-append EXTRA_LDFLAGS -static
msg-result "Trying to link statically"
} else {
define-append EXTRA_CFLAGS -DFOSSIL_DYNAMIC_BUILD=1
define FOSSIL_DYNAMIC_BUILD
}
# Check for libraries that need to be sorted out early
cc-check-function-in-lib iconv iconv
cc-check-function-in-lib sin m
cc-check-function-in-lib dlopen dl
# Helper for OpenSSL checking
proc check-for-openssl {msg {cflags {}} {libs {-lssl -lcrypto -lpthread}}} {
msg-checking "Checking for $msg..."
set rc 0
if {[is_mingw]} {
lappend libs -lgdi32 -lwsock32 -lcrypt32
}
if {[info exists ::zlib_lib]} {
lappend libs $::zlib_lib
}
msg-quiet cc-with [list -cflags $cflags -libs $libs] {
if {[cc-check-includes openssl/ssl.h] && \
[cc-check-functions SSL_new]} {
incr rc
}
}
if {!$rc && ![is_mingw]} {
# On some systems, OpenSSL appears to require -ldl to link.
lappend libs -ldl
msg-quiet cc-with [list -cflags $cflags -libs $libs] {
if {[cc-check-includes openssl/ssl.h] && \
[cc-check-functions SSL_new]} {
incr rc
}
}
}
if {$rc} {
msg-result "ok"
return 1
} else {
msg-result "no"
return 0
}
}
#
# Check for zlib, using the given location if specified
#
proc handle-zlib {} {
set ::zlibpath [opt-val with-zlib]; # used by downstream tcl tests
if {$::zlibpath eq "tree"} {
set ::zlibdir [file dirname $::autosetup(dir)]/compat/zlib
if {![file isdirectory $::zlibdir]} {
user-error "The zlib in source tree directory does not exist"
} elseif { ([llength [glob -nocomplain -directory $::zlibdir libz*]] == 0) } {
user-error "With --with-zlib=tree, $::zlibdir must be configured and built first."
}
cc-with [list -cflags "-I$::zlibdir -L$::zlibdir"]
define-append EXTRA_CFLAGS -I$::zlibdir
define-append LIBS $::zlibdir/libz.a
set ::zlib_lib $::zlibdir/libz.a
msg-result "Using zlib in source tree"
} else {
set cftry {""}
set ldtry {""}
if {$::zlibpath ni {auto ""}} {
lappend cftry "-I$::zlibpath"
lappend cftry "-I$::zlibpath/include"
lappend ldtry "-L$::zlibpath"
lappend ldtry "-L$::zlibpath/lib"
}
# Reverse the list of tests so we check most-specific to least, else
# platform devel files will shadow local --with-zlib overrides.
foreach c [lreverse $cftry] {
if {[cc-with [list -cflags $c] {cc-check-includes zlib.h}]} {
if {$c eq ""} {
msg-result "Found zlib.h in default include path"
} else {
define-append EXTRA_CFLAGS "$c"
msg-result "Found zlib.h via $c"
}
set cfound $c
break
}
}
if {![info exists cfound]} {
user-error "zlib.h not found; either install it or specify its location via --with-zlib"
}
foreach lcheck [lreverse $ldtry] {
if {[cc-with [list -cflags "$cfound $lcheck"] {check-function-in-lib inflateEnd z}]} {
if {$lcheck eq ""} {
msg-result "Linked to zlib via default library path"
} else {
define-append EXTRA_LDFLAGS "$lcheck"
msg-result "Linked to zlib via $lcheck"
}
if {![check-function-in-lib compressBound z]} {
puts "Notice: disabling zlib compression in the SQL shell"
define-append SQLITE_OPTIONS_EXT {-USQLITE_HAVE_ZLIB}
}
break
}
}
set ::zlib_lib -lz
}
}; # handle-zlib
handle-zlib
#
# Handle the --with-openssl flag and, incidentally, update @LIBS@ for
# zlib if openssl is _not_ used (if it is, we get zlib via libssl).
#
# This function should be called as late as possible in the configure
# script to avoid that its updates to @LIBS@ break tests which follow
# it when a custom local build of openssl is used, as discussed in
# <https://fossil-scm.org/forum/forumpost/15e3d9cdc137030c>.
#
proc handle-with-openssl {} {
set ssldirs [opt-val with-openssl]
if {$ssldirs ne "none"} {
set found 0
if {$ssldirs eq "tree"} {
set ssldir [file dirname $::autosetup(dir)]/compat/openssl
if {![file isdirectory $ssldir]} {
user-error "The OpenSSL in source tree directory does not exist"
}
set msg "openssl in $ssldir"
set cflags "-I$ssldir/include"
set ldflags "-L$ssldir"
set ssllibs "$ssldir/libssl.a $ssldir/libcrypto.a -lpthread"
set found [check-for-openssl "openssl in source tree" "$cflags $ldflags" $ssllibs]
} else {
if {$ssldirs in {auto ""}} {
catch {
# TODO?: use autosetup's pkg-config support
set cflags [exec pkg-config openssl --cflags-only-I]
set ldflags [exec pkg-config openssl --libs-only-L]
set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
} msg
if {!$found} {
set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl \
/usr/pkg /usr/local /usr /usr/local/opt/openssl \
/opt/homebrew/opt/openssl"
}
}
if {!$found} {
foreach dir $ssldirs {
if {$dir eq ""} {
set msg "system openssl"
set cflags ""
set ldflags ""
} else {
set msg "openssl in $dir"
set cflags "-I$dir/include"
if {[file readable $dir/libssl.a]} {
set ldflags -L$dir
} elseif {[file readable $dir/lib/libssl.a]} {
set ldflags -L$dir/lib
} elseif {[file isdir $dir/lib]} {
set ldflags "-L$dir -L$dir/lib"
} else {
set ldflags -L$dir
}
}
if {[check-for-openssl $msg "$cflags $ldflags"]} {
incr found
break
}
if {$dir ne ""} {
set ldflags ""
set msg "static build of openssl in $dir"
set ssllibs "$dir/libssl.a $dir/libcrypto.a -lpthread"
if {[check-for-openssl $msg "$cflags $ldflags" $ssllibs]} {
incr found
break
}
# This test should arguably fail here if --with-openssl=X
# points to an invalid X.
}
}
}
}
if {$found} {
define FOSSIL_ENABLE_SSL
define-append EXTRA_CFLAGS $cflags
define-append EXTRA_LDFLAGS $ldflags
if {[info exists ssllibs]} {
define-append LIBS $ssllibs
} else {
define-append LIBS -lssl -lcrypto
}
if {[info exists ::zlib_lib]} {
define-append LIBS $::zlib_lib
}
if {[is_mingw]} {
define-append LIBS -lgdi32 -lwsock32 -lcrypt32
}
msg-result "HTTPS support enabled"
# Silence OpenSSL deprecation warnings on Mac OS X 10.7.
if {[string match *-darwin* [get-define host]]} {
if {[cctest -cflags {-Wdeprecated-declarations}]} {
define-append EXTRA_CFLAGS -Wdeprecated-declarations
}
}
} else {
user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
}
} else {
if {[info exists ::zlib_lib]} {
define-append LIBS $::zlib_lib
}
}
}; # handle-with-openssl
#
# CFLAGS_INCLUDE is ONLY for -I... flags and their order is
# significant so that --with-sqlite=PATH's header can shadow our
# own. <s>One caveat with this is that we cannot point
# --with-sqlite=PATH to the root of sqlite3's own build tree because
# that dir has a config.h which ends up shadowing src/config.h,
# breaking our build.</s> (That is no longer true: that that config.h
# was renamed to sqlite_cfg.h at some point.)
#
define CFLAGS_INCLUDE {}
########################################################################
# --with-sqlite=PATH checks for the first it finds of the following...
# - PATH/sqlite3.c and PATH/sqlite3.h
# - PATH/sqlite3.o (and assumes sqlite3.h is with it)
# - PATH/lib/libsqlite3* and PATH/include/sqlite3.h
proc handle-with-sqlite {} {
set sq3path [opt-val with-sqlite]
define SQLITE3_SRC.2 {}
define SQLITE3_OBJ.2 {}
define SQLITE3_SHELL_SRC.2 {$(SQLITE3_SHELL_SRC.0)}
if {$sq3path in {tree ""}} {
msg-result "Using sqlite3.c from this source tree."
} else {
# SQLITE3_ORIGIN:
# 0 = local source tree
# 1 = use external lib or sqlite3.o
# 2 = use external sqlite3.c and (if found) shell.c
define USE_SYSTEM_SQLITE 1
define SQLITE3_ORIGIN 2
if {$sq3path != "auto"} {
if {([file exists $sq3path/sqlite3.c]) &&
([file exists $sq3path/sqlite3.h]) } {
# Prefer sqlite3.[ch] if found.
define SQLITE3_SRC.2 $sq3path/sqlite3.c
define SQLITE3_OBJ.2 {$(SQLITE3_OBJ.0)}
define USE_SYSTEM_SQLITE 2
define SQLITE3_ORIGIN 2
if {[file exists $sq3path/shell.c]} {
define SQLITE3_SHELL_SRC.2 $sq3path/shell.c
}
define-append CFLAGS_INCLUDE -I$sq3path
define-append EXTRA_LDFLAGS -lpthread
# ^^^ additional -lXXX flags are conservative estimates
msg-result "Using sqlite3.c and sqlite3.h from $sq3path"
} elseif {[file exists $sq3path/sqlite3.o]} {
# Use sqlite3.o if found.
define SQLITE3_OBJ.2 $sq3path/sqlite3.o
define-append CFLAGS_INCLUDE -I$sq3path
define-append EXTRA_LDFLAGS $sq3path/sqlite3.o -lpthread
# ^^^ additional -lXXX flags are conservative estimates
msg-result "Using sqlite3.o from $sq3path"
} elseif { ([llength [glob -nocomplain -directory $sq3path/lib libsqlite3*]] != 0) \
&& ([file exists $sq3path/include/sqlite3.h]) } {
# e.g. --with-sqlite=/usr/local. Try $sq3path/lib/libsqlite3*
# and $sq3path/include/sqlite3.h
define-append CFLAGS_INCLUDE -I$sq3path/include
define-append EXTRA_LDFLAGS -L$sq3path/lib -lsqlite3 -lpthread
# ^^^ additional -lXXX flags are conservative estimates
msg-result "Using -lsqlite3 from $sq3path"
} else {
# Assume $sq3path holds both the lib and header
cc-with [list -cflags "-I$sq3path -L$sq3path"]
define-append CFLAGS_INCLUDE -I$sq3path
define-append EXTRA_LDFLAGS -L$sq3path -lsqlite3 -lpthread
# ^^^ additional -lXXX flags are conservative estimates
msg-result "Using -lsqlite3 from $sq3path"
}
} elseif {![cc-check-includes sqlite3.h] || ![check-function-in-lib sqlite3_open_v2 sqlite3]} {
user-error "libsqlite3 not found please install it or specify the location with --with-sqlite"
}
}
}; # handle-with-sqlite
handle-with-sqlite
define-append CFLAGS_INCLUDE {-I. -I$(SRCDIR) -I$(SRCDIR_extsrc)}; # must be after handle-with-sqlite
#
# Handle the --with-tcl flag.
#
proc handle-with-tcl {} {
set tclpath [opt-val with-tcl]
if {$tclpath eq ""} {
return
}
set tclprivatestubs [opt-bool with-tcl-private-stubs]
# Note parse-tclconfig-sh is in autosetup/local.tcl
if {$tclpath eq "1"} {
set tcldir [file dirname $::autosetup(dir)]/compat/tcl-8.6
if {$tclprivatestubs} {
set tclconfig(TCL_INCLUDE_SPEC) -I$tcldir/generic
set tclconfig(TCL_VERSION) {Private Stubs}
set tclconfig(TCL_PATCH_LEVEL) {}
set tclconfig(TCL_PREFIX) $tcldir
set tclconfig(TCL_LD_FLAGS) { }
} else {
# Use the system Tcl. Look in some likely places.
array set tclconfig [parse-tclconfig-sh \
$tcldir/unix $tcldir/win \
/usr /usr/local /usr/share /opt/local]
set msg "on your system"
}
} else {
array set tclconfig [parse-tclconfig-sh $tclpath]
set msg "at $tclpath"
}
if {[opt-bool static]} {
set tclconfig(TCL_LD_FLAGS) { }
}
if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
user-error "Cannot find Tcl $msg"
}
set tclstubs [opt-bool with-tcl-stubs]
if {$tclprivatestubs} {
define FOSSIL_ENABLE_TCL_PRIVATE_STUBS
define USE_TCL_STUBS
} elseif {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
define FOSSIL_ENABLE_TCL_STUBS
define USE_TCL_STUBS
} else {
set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
}
set cflags $tclconfig(TCL_INCLUDE_SPEC)
if {!$tclprivatestubs} {
set foundtcl 0; # Did we find a working Tcl library?
cc-with [list -cflags $cflags -libs $libs] {
if {$tclstubs} {
if {[cc-check-functions Tcl_InitStubs]} {
set foundtcl 1
}
} else {
if {[cc-check-functions Tcl_CreateInterp]} {
set foundtcl 1
}
}
}
if {!$foundtcl && [string match *-lieee* $libs]} {
# On some systems, using "-lieee" from TCL_LIB_SPEC appears
# to cause issues.
msg-result "Removing \"-lieee\" and retrying for Tcl..."
set libs [string map [list -lieee ""] $libs]
cc-with [list -cflags $cflags -libs $libs] {
if {$tclstubs} {
if {[cc-check-functions Tcl_InitStubs]} {
set foundtcl 1
}
} else {
if {[cc-check-functions Tcl_CreateInterp]} {
set foundtcl 1
}
}
}
}
if {!$foundtcl && ![string match *-lpthread* $libs]} {
# On some systems, TCL_LIB_SPEC appears to be missing
# "-lpthread". Try adding it.
msg-result "Adding \"-lpthread\" and retrying for Tcl..."
set libs "$libs -lpthread"
cc-with [list -cflags $cflags -libs $libs] {
if {$tclstubs} {
if {[cc-check-functions Tcl_InitStubs]} {
set foundtcl 1
}
} else {
if {[cc-check-functions Tcl_CreateInterp]} {
set foundtcl 1
}
}
}
}
if {!$foundtcl} {
if {$tclstubs} {
user-error "Cannot find a usable Tcl stubs library $msg"
} else {
user-error "Cannot find a usable Tcl library $msg"
}
}
}
set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
if {!$tclprivatestubs} {
define-append LIBS $libs
}
define-append EXTRA_CFLAGS $cflags
define-append CFLAGS $cflags
if {[info exists ::zlibpath] && $::zlibpath eq "tree"} {
#
# NOTE: When using zlib in the source tree, prevent Tcl from
# pulling in the system one.
#
set tclconfig(TCL_LD_FLAGS) [string map [list -lz ""] \
$tclconfig(TCL_LD_FLAGS)]
}
#
# NOTE: Remove "-ldl" from the TCL_LD_FLAGS because it will be
# be checked for near the bottom of this file.
#
set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \
$tclconfig(TCL_LD_FLAGS)]
define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
define FOSSIL_ENABLE_TCL
}; # handle-with-tcl
handle-with-tcl
# Network functions require libraries on some systems
cc-check-function-in-lib gethostbyname nsl
if {![cc-check-function-in-lib socket {socket network}]} {
# Last resort, may be Windows
if {[is_mingw]} {
define-append LIBS -lwsock32
}
}
# Some systems (ex: SunOS) require -lrt in order to use nanosleep
cc-check-function-in-lib nanosleep rt
# The SMTP module requires special libraries and headers for MX DNS
# record lookups and such.
cc-check-includes arpa/nameser.h
cc-include-needs bind/resolv.h netinet/in.h
cc-check-includes bind/resolv.h
cc-check-includes resolv.h
if { !(([cc-check-function-in-lib dn_expand resolv] ||
[cc-check-function-in-lib ns_name_uncompress {bind resolv}] ||
[cc-check-function-in-lib __ns_name_uncompress {bind resolv}]) &&
([cc-check-function-in-lib ns_parserr {bind resolv}] ||
[cc-check-function-in-lib __ns_parserr {bind resolv}]) &&
([cc-check-function-in-lib res_query {bind resolv}] ||
[cc-check-function-in-lib __res_query {bind resolv}]))} {
msg-result "WARNING: SMTP feature will not be able to look up local MX."
}
cc-check-function-in-lib res_9_ns_initparse resolv
# Other nonstandard function checks
cc-check-functions utime
cc-check-functions usleep
cc-check-functions strchrnul
cc-check-functions pledge
cc-check-functions backtrace
# Termux on Android adds "getpass(char *)" to unistd.h, so check this so we
# guard against including it again; use cctest as cc-check-functions and
# cctest_function check for "getpass()" with no args and fail
if {[cctest -link 1 -includes {unistd.h} -code "getpass(0);"]} {
define FOSSIL_HAVE_GETPASS 1
msg-result "Found getpass() with unistd.h"
}
# Check for getloadavg(), and if it doesn't exist, define FOSSIL_OMIT_LOAD_AVERAGE
if {![cc-check-functions getloadavg] ||
![cctest -link 1 -includes {unistd.h} -code "double a\[3\]; getloadavg(a,3);"]} {
define FOSSIL_OMIT_LOAD_AVERAGE 1
msg-result "Load average support unavailable"
}
# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
if {![cc-check-functions getpassphrase]} {
# Haiku needs this
cc-check-function-in-lib getpass bsd
}
# Check for the FuseFS library
if {[opt-bool fusefs]} {
if {[opt-bool static]} {
msg-result "FuseFS support disabled due to -static"
} elseif {[cc-check-function-in-lib fuse_mount fuse]} {
define-append EXTRA_CFLAGS -DFOSSIL_HAVE_FUSEFS
define FOSSIL_HAVE_FUSEFS 1
msg-result "FuseFS support enabled"
}
}
########################################################################
# Checks the compiler for compile_commands.json support.
#
# Returns 1 if supported, else 0. Defines MAKE_COMPILATION_DB to "yes"
# if supported, "no" if not.
proc check-compile-commands {} {
msg-checking "compile_commands.json support... "
if {[cctest -lang c -cflags {/dev/null -MJ} -source {}]} {
# This test reportedly incorrectly succeeds on one of
# Martin G.'s older systems.
msg-result "compiler supports compile_commands.json"
define MAKE_COMPILATION_DB yes
return 1
} else {
msg-result "compiler does not support compile_commands.json"
define MAKE_COMPILATION_DB no
return 0
}
}
define MAKE_COMPILATION_DB no
if {!$outOfTreeBuild} {
if {[opt-bool compile-commands]} {
check-compile-commands
} else {
puts "Use --compile-commands to enable check for compile-commands-capable compiler."
}
} else {
puts "Disabling compile_commands.json check for out-of-tree build."
# This is an attempt to resolve the problem reported at
# https://fossil-scm.org/forum/forumpost/d19061d09a8179d0
}
# Add -fsanitize compile and link options late: we don't want the C
# checks above to run with those sanitizers enabled. It can not only
# be pointless, it can actually break correct tests.
set fsan [opt-val with-sanitizer]
if {[string length $fsan]} {
define-append EXTRA_CFLAGS -fsanitize=$fsan
define-append EXTRA_LDFLAGS -fsanitize=$fsan
if {[string first "undefined" $fsan] != -1} {
# We need to link with libubsan if we're compiling under
# GCC with -fsanitize=undefined.
cc-check-function-in-lib __ubsan_handle_add_overflow ubsan
}
}
########################################################################
# @proj-check-emsdk
#
# Emscripten is used for doing in-tree builds of web-based WASM stuff,
# as opposed to WASI-based WASM or WASM binaries we import from other
# places. This is only set up for Unix-style OSes and is untested
|
| ︙ | ︙ | |||
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 |
make-template tools/emcc.sh.in
catch {exec chmod u+x tools/emcc.sh}
} else {
define EMCC_WRAPPER ""
define EMCC_OPT ""
catch {exec rm -f tools/emcc.sh}
}
# Tag container builds with a prefix of the checkin ID of the version
# of Fossil each one contains. This not only allows multiple images
# to coexist and multiple containers to be created unamgiguosly from
# them, it also changes the URL we fetch the source tarball from, so
# repeated builds of a given version generate and fetch the source
# tarball once only, keeping it in the local Docker/Podman cache.
set ci [readfile "$::autosetup(srcdir)/manifest.uuid"]
define FOSSIL_CI_PFX [string range $ci 0 11]
make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
make-template tools/emcc.sh.in
catch {exec chmod u+x tools/emcc.sh}
} else {
define EMCC_WRAPPER ""
define EMCC_OPT ""
catch {exec rm -f tools/emcc.sh}
}
handle-with-openssl
# Finally, append libraries that must be last. This matters more on some
# OSes than others, but is most broadly required for static linking.
if {[opt-bool static]} {
# Linux can only infer the dependency on pthread from OpenSSL when
# doing dynamic linkage.
define-append LIBS -lpthread
}
apply {{} {
# This started out as a workaround for getting the ordering of -ldl
# correct in conjunction with openssl in some environments. Then it
# evolved into a more generic preemptive portability workaround to
# ensure that certain libraries are always appended to the global
# LIBS list if they exist on the system. Based on a /chat discussion
# on 2025-02-27 in the context of check-in [8d3b9bf4d4].
#
# Note that [move-lib-to-end] and [lib-actually-exists] are in
# autosetup/local.tcl.
set libs [get-define LIBS]
#puts "**** 1 LIBS: $libs"
foreach ll {-ldl -lpthread -lm} {
if {![move-lib-to-end $ll $libs libs]} {
# $ll was not in the list
if {[lib-actually-exists $ll]} {
# Add it to the list "just in case." This will be a no-op on
# systems where the lib is not actually used.
lappend libs $ll
}
}
}
#puts "**** 2 LIBS: $libs"
define LIBS [join $libs " "]
}}
# Tag container builds with a prefix of the checkin ID of the version
# of Fossil each one contains. This not only allows multiple images
# to coexist and multiple containers to be created unamgiguosly from
# them, it also changes the URL we fetch the source tarball from, so
# repeated builds of a given version generate and fetch the source
# tarball once only, keeping it in the local Docker/Podman cache.
set ci [readfile "$::autosetup(srcdir)/manifest.uuid"]
define FOSSIL_CI_PFX [string range $ci 0 11]
make-template Makefile.in
make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
|
Changes to autosetup/local.tcl.
| ︙ | ︙ | |||
25 26 27 28 29 30 31 |
if {[regexp {^(TCL_[^=]*)=(.*)$} $line -> name value]} {
set value [regsub -all {\$\{.*\}} $value ""]
set tclconfig($name) [string trim $value ']
}
}
return [array get tclconfig]
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
if {[regexp {^(TCL_[^=]*)=(.*)$} $line -> name value]} {
set value [regsub -all {\$\{.*\}} $value ""]
set tclconfig($name) [string trim $value ']
}
}
return [array get tclconfig]
}
#
# Given a library link flag, e.g. -lfoo, returns 1 if that library can
# actually be linked to, else returns 0.
proc lib-actually-exists {linkFlag} {
cctest -link 1 -code "void libActuallyExists(void){}" -libs $linkFlag
}
#
# Given a library flag, e.g. -lfoo, a list of libs, e.g. {-lfoo -lbar
# -lbaz}, and a target variable name, this function appends all
# entries of $libList which do not match $flag to $tgtVar, then
# appends $flag to the end of $tgtVar. Returns the number of matches
# found.
proc move-lib-to-end {flag libList tgtVar} {
upvar $tgtVar tgt
set tgt {}
set found 0
foreach e $libList {
if {$flag eq $e} {
incr found
} else {
lappend tgt $e
}
}
if {$found} {
lappend tgt $flag
}
return $found
}
|
Added extsrc/linenoise-win32.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 |
/* this code is not standalone
* it is included into linenoise.c
* for windows.
* It is deliberately kept separate so that
* applications that have no need for windows
* support can omit this
*/
static DWORD orig_consolemode = 0;
static int flushOutput(struct current *current);
static void outputNewline(struct current *current);
static void refreshStart(struct current *current)
{
(void)current;
}
static void refreshEnd(struct current *current)
{
(void)current;
}
static void refreshStartChars(struct current *current)
{
assert(current->output == NULL);
/* We accumulate all output here */
current->output = sb_alloc();
#ifdef USE_UTF8
current->ubuflen = 0;
#endif
}
static void refreshNewline(struct current *current)
{
DRL("<nl>");
outputNewline(current);
}
static void refreshEndChars(struct current *current)
{
assert(current->output);
flushOutput(current);
sb_free(current->output);
current->output = NULL;
}
static int enableRawMode(struct current *current) {
DWORD n;
INPUT_RECORD irec;
current->outh = GetStdHandle(STD_OUTPUT_HANDLE);
current->inh = GetStdHandle(STD_INPUT_HANDLE);
if (!PeekConsoleInput(current->inh, &irec, 1, &n)) {
return -1;
}
if (getWindowSize(current) != 0) {
return -1;
}
if (GetConsoleMode(current->inh, &orig_consolemode)) {
SetConsoleMode(current->inh, ENABLE_PROCESSED_INPUT);
}
#ifdef USE_UTF8
/* XXX is this the right thing to do? */
SetConsoleCP(65001);
#endif
return 0;
}
static void disableRawMode(struct current *current)
{
SetConsoleMode(current->inh, orig_consolemode);
}
void linenoiseClearScreen(void)
{
/* XXX: This is ugly. Should just have the caller pass a handle */
struct current current;
current.outh = GetStdHandle(STD_OUTPUT_HANDLE);
if (getWindowSize(¤t) == 0) {
COORD topleft = { 0, 0 };
DWORD n;
FillConsoleOutputCharacter(current.outh, ' ',
current.cols * current.rows, topleft, &n);
FillConsoleOutputAttribute(current.outh,
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN,
current.cols * current.rows, topleft, &n);
SetConsoleCursorPosition(current.outh, topleft);
}
}
static void cursorToLeft(struct current *current)
{
COORD pos;
DWORD n;
pos.X = 0;
pos.Y = (SHORT)current->y;
FillConsoleOutputAttribute(current->outh,
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN, current->cols, pos, &n);
current->x = 0;
}
#ifdef USE_UTF8
static void flush_ubuf(struct current *current)
{
COORD pos;
DWORD nwritten;
pos.Y = (SHORT)current->y;
pos.X = (SHORT)current->x;
SetConsoleCursorPosition(current->outh, pos);
WriteConsoleW(current->outh, current->ubuf, current->ubuflen, &nwritten, 0);
current->x += current->ubufcols;
current->ubuflen = 0;
current->ubufcols = 0;
}
static void add_ubuf(struct current *current, int ch)
{
/* This code originally by: Author: Mark E. Davis, 1994. */
static const int halfShift = 10; /* used for shifting by 10 bits */
static const DWORD halfBase = 0x0010000UL;
static const DWORD halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START 0xD800
#define UNI_SUR_HIGH_END 0xDBFF
#define UNI_SUR_LOW_START 0xDC00
#define UNI_SUR_LOW_END 0xDFFF
#define UNI_MAX_BMP 0x0000FFFF
if (ch > UNI_MAX_BMP) {
/* convert from unicode to utf16 surrogate pairs
* There is always space for one extra word in ubuf
*/
ch -= halfBase;
current->ubuf[current->ubuflen++] = (WORD)((ch >> halfShift) + UNI_SUR_HIGH_START);
current->ubuf[current->ubuflen++] = (WORD)((ch & halfMask) + UNI_SUR_LOW_START);
}
else {
current->ubuf[current->ubuflen++] = ch;
}
current->ubufcols += utf8_width(ch);
if (current->ubuflen >= UBUF_MAX_CHARS) {
flush_ubuf(current);
}
}
#endif
static int flushOutput(struct current *current)
{
const char *pt = sb_str(current->output);
int len = sb_len(current->output);
#ifdef USE_UTF8
/* convert utf8 in current->output into utf16 in current->ubuf
*/
while (len) {
int ch;
int n = utf8_tounicode(pt, &ch);
pt += n;
len -= n;
add_ubuf(current, ch);
}
flush_ubuf(current);
#else
DWORD nwritten;
COORD pos;
pos.Y = (SHORT)current->y;
pos.X = (SHORT)current->x;
SetConsoleCursorPosition(current->outh, pos);
WriteConsoleA(current->outh, pt, len, &nwritten, 0);
current->x += len;
#endif
sb_clear(current->output);
return 0;
}
static int outputChars(struct current *current, const char *buf, int len)
{
if (len < 0) {
len = strlen(buf);
}
assert(current->output);
sb_append_len(current->output, buf, len);
return 0;
}
static void outputNewline(struct current *current)
{
/* On the last row output a newline to force a scroll */
if (current->y + 1 == current->rows) {
outputChars(current, "\n", 1);
}
flushOutput(current);
current->x = 0;
current->y++;
}
static void setOutputHighlight(struct current *current, const int *props, int nprops)
{
int colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
int bold = 0;
int reverse = 0;
int i;
for (i = 0; i < nprops; i++) {
switch (props[i]) {
case 0:
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
bold = 0;
reverse = 0;
break;
case 1:
bold = FOREGROUND_INTENSITY;
break;
case 7:
reverse = 1;
break;
case 30:
colour = 0;
break;
case 31:
colour = FOREGROUND_RED;
break;
case 32:
colour = FOREGROUND_GREEN;
break;
case 33:
colour = FOREGROUND_RED | FOREGROUND_GREEN;
break;
case 34:
colour = FOREGROUND_BLUE;
break;
case 35:
colour = FOREGROUND_RED | FOREGROUND_BLUE;
break;
case 36:
colour = FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
case 37:
colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN;
break;
}
}
flushOutput(current);
if (reverse) {
SetConsoleTextAttribute(current->outh, BACKGROUND_INTENSITY);
}
else {
SetConsoleTextAttribute(current->outh, colour | bold);
}
}
static void eraseEol(struct current *current)
{
COORD pos;
DWORD n;
pos.X = (SHORT) current->x;
pos.Y = (SHORT) current->y;
FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n);
}
static void setCursorXY(struct current *current)
{
COORD pos;
pos.X = (SHORT) current->x;
pos.Y = (SHORT) current->y;
SetConsoleCursorPosition(current->outh, pos);
}
static void setCursorPos(struct current *current, int x)
{
current->x = x;
setCursorXY(current);
}
static void cursorUp(struct current *current, int n)
{
current->y -= n;
setCursorXY(current);
}
static void cursorDown(struct current *current, int n)
{
current->y += n;
setCursorXY(current);
}
static int fd_read(struct current *current)
{
while (1) {
INPUT_RECORD irec;
DWORD n;
if (WaitForSingleObject(current->inh, INFINITE) != WAIT_OBJECT_0) {
break;
}
if (!ReadConsoleInputW(current->inh, &irec, 1, &n)) {
break;
}
if (irec.EventType == KEY_EVENT) {
KEY_EVENT_RECORD *k = &irec.Event.KeyEvent;
if (k->bKeyDown || k->wVirtualKeyCode == VK_MENU) {
if (k->dwControlKeyState & ENHANCED_KEY) {
switch (k->wVirtualKeyCode) {
case VK_LEFT:
return SPECIAL_LEFT;
case VK_RIGHT:
return SPECIAL_RIGHT;
case VK_UP:
return SPECIAL_UP;
case VK_DOWN:
return SPECIAL_DOWN;
case VK_INSERT:
return SPECIAL_INSERT;
case VK_DELETE:
return SPECIAL_DELETE;
case VK_HOME:
return SPECIAL_HOME;
case VK_END:
return SPECIAL_END;
case VK_PRIOR:
return SPECIAL_PAGE_UP;
case VK_NEXT:
return SPECIAL_PAGE_DOWN;
case VK_RETURN:
return k->uChar.UnicodeChar;
}
}
/* Note that control characters are already translated in AsciiChar */
else if (k->wVirtualKeyCode == VK_CONTROL)
continue;
else {
return k->uChar.UnicodeChar;
}
}
}
}
return -1;
}
static int getWindowSize(struct current *current)
{
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(current->outh, &info)) {
return -1;
}
current->cols = info.dwSize.X;
current->rows = info.dwSize.Y;
if (current->cols <= 0 || current->rows <= 0) {
current->cols = 80;
return -1;
}
current->y = info.dwCursorPosition.Y;
current->x = info.dwCursorPosition.X;
return 0;
}
|
Changes to extsrc/linenoise.c.
| ︙ | ︙ | |||
890 891 892 893 894 895 896 897 898 899 900 901 902 903 |
int colsright; /* refreshLine() cached cols for insert_char() optimisation */
int colsleft; /* refreshLine() cached cols for remove_char() optimisation */
const char *prompt;
stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
stringbuf *output; /* used only during refreshLine() - output accumulator */
#if defined(USE_TERMIOS)
int fd; /* Terminal fd */
#elif defined(USE_WINCONSOLE)
HANDLE outh; /* Console output handle */
HANDLE inh; /* Console input handle */
int rows; /* Screen rows */
int x; /* Current column during output */
int y; /* Current row */
#ifdef USE_UTF8
| > | 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 |
int colsright; /* refreshLine() cached cols for insert_char() optimisation */
int colsleft; /* refreshLine() cached cols for remove_char() optimisation */
const char *prompt;
stringbuf *capture; /* capture buffer, or NULL for none. Always null terminated */
stringbuf *output; /* used only during refreshLine() - output accumulator */
#if defined(USE_TERMIOS)
int fd; /* Terminal fd */
int pending; /* pending char fd_read_char() */
#elif defined(USE_WINCONSOLE)
HANDLE outh; /* Console output handle */
HANDLE inh; /* Console input handle */
int rows; /* Screen rows */
int x; /* Current column during output */
int y; /* Current row */
#ifdef USE_UTF8
|
| ︙ | ︙ | |||
1119 1120 1121 1122 1123 1124 1125 |
/* local modes - choing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* control chars - set return condition: min number of bytes and timer.
* We want read to return every single byte, without timeout. */
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
| | > > > | | | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 |
/* local modes - choing off, canonical off, no extended functions,
* no signal chars (^Z,^C) */
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
/* control chars - set return condition: min number of bytes and timer.
* We want read to return every single byte, without timeout. */
raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */
/* put terminal in raw mode. Because we aren't changing any output
* settings we don't need to use TCSADRAIN and I have seen that hang on
* OpenBSD when running under a pty
*/
if (tcsetattr(current->fd,TCSANOW,&raw) < 0) {
goto fatal;
}
rawmode = 1;
return 0;
}
static void disableRawMode(struct current *current) {
/* Don't even check the return value as it's too late. */
if (rawmode && tcsetattr(current->fd,TCSANOW,&orig_termios) != -1)
rawmode = 0;
}
/* At exit we'll try to fix the terminal to the initial conditions. */
static void linenoiseAtExit(void) {
if (rawmode) {
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
}
linenoiseHistoryFree();
}
/* gcc/glibc insists that we care about the return code of write!
* Clarification: This means that a void-cast like "(void) (EXPR)"
* does not work.
|
| ︙ | ︙ | |||
1228 1229 1230 1231 1232 1233 1234 |
void linenoiseClearScreen(void)
{
IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
}
/**
| | | > > > > > > | | > > > > | | > > > > > > > > > | > > > | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 |
void linenoiseClearScreen(void)
{
IGNORE_RC(write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7));
}
/**
* Reads a char from 'current->fd', waiting at most 'timeout' milliseconds.
*
* A timeout of -1 means to wait forever.
*
* Returns -1 if no char is received within the time or an error occurs.
*/
static int fd_read_char(struct current *current, int timeout)
{
struct pollfd p;
unsigned char c;
if (current->pending) {
c = current->pending;
current->pending = 0;
return c;
}
p.fd = current->fd;
p.events = POLLIN;
if (poll(&p, 1, timeout) == 0) {
/* timeout */
return -1;
}
if (read(current->fd, &c, 1) != 1) {
return -1;
}
return c;
}
/**
* Reads a complete utf-8 character
* and returns the unicode value, or -1 on error.
*/
static int fd_read(struct current *current)
{
#ifdef USE_UTF8
char buf[MAX_UTF8_LEN];
int n;
int i;
int c;
if (current->pending) {
buf[0] = current->pending;
current->pending = 0;
}
else if (read(current->fd, &buf[0], 1) != 1) {
return -1;
}
n = utf8_charlen(buf[0]);
if (n < 1) {
return -1;
}
for (i = 1; i < n; i++) {
if (read(current->fd, &buf[i], 1) != 1) {
return -1;
}
}
/* decode and return the character */
utf8_tounicode(buf, &c);
return c;
#else
return fd_read_char(current, -1);
#endif
}
/**
* Stores the current cursor column in '*cols'.
* Returns 1 if OK, or 0 if failed to determine cursor pos.
*/
static int queryCursor(struct current *current, int* cols)
{
struct esc_parser parser;
int ch;
/* Unfortunately we don't have any persistent state, so assume
* a process will only ever interact with one terminal at a time.
*/
static int query_cursor_failed;
if (query_cursor_failed) {
/* If it ever fails, don't try again */
return 0;
}
/* Should not be buffering this output, it needs to go immediately */
assert(current->output == NULL);
/* control sequence - report cursor location */
outputChars(current, "\x1b[6n", -1);
/* Parse the response: ESC [ rows ; cols R */
initParseEscapeSeq(&parser, 'R');
while ((ch = fd_read_char(current, 100)) > 0) {
switch (parseEscapeSequence(&parser, ch)) {
default:
continue;
case EP_END:
if (parser.numprops == 2 && parser.props[1] < 1000) {
*cols = parser.props[1];
return 1;
}
break;
case EP_ERROR:
/* Push back the character that caused the error */
current->pending = ch;
break;
}
/* failed */
break;
}
query_cursor_failed = 1;
return 0;
}
/**
* Updates current->cols with the current window size (width)
*/
static int getWindowSize(struct current *current)
|
| ︙ | ︙ | |||
1384 1385 1386 1387 1388 1389 1390 | * chars to determine if this is a known special key. * * Returns SPECIAL_NONE if unrecognised, or -1 if EOF. * * If no additional char is received within a short time, * CHAR_ESCAPE is returned. */ | | | | | 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 |
* chars to determine if this is a known special key.
*
* Returns SPECIAL_NONE if unrecognised, or -1 if EOF.
*
* If no additional char is received within a short time,
* CHAR_ESCAPE is returned.
*/
static int check_special(struct current *current)
{
int c = fd_read_char(current, 50);
int c2;
if (c < 0) {
return CHAR_ESCAPE;
}
else if (c >= 'a' && c <= 'z') {
/* esc-a => meta-a */
return meta(c);
}
c2 = fd_read_char(current, 50);
if (c2 < 0) {
return c2;
}
if (c == '[' || c == 'O') {
/* Potential arrow key */
switch (c2) {
case 'A':
|
| ︙ | ︙ | |||
1420 1421 1422 1423 1424 1425 1426 |
return SPECIAL_END;
case 'H':
return SPECIAL_HOME;
}
}
if (c == '[' && c2 >= '1' && c2 <= '8') {
/* extended escape */
| | | | 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 |
return SPECIAL_END;
case 'H':
return SPECIAL_HOME;
}
}
if (c == '[' && c2 >= '1' && c2 <= '8') {
/* extended escape */
c = fd_read_char(current, 50);
if (c == '~') {
switch (c2) {
case '2':
return SPECIAL_INSERT;
case '3':
return SPECIAL_DELETE;
case '5':
return SPECIAL_PAGE_UP;
case '6':
return SPECIAL_PAGE_DOWN;
case '7':
return SPECIAL_HOME;
case '8':
return SPECIAL_END;
}
}
while (c != -1 && c != '~') {
/* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */
c = fd_read_char(current, 50);
}
}
return SPECIAL_NONE;
}
#endif
|
| ︙ | ︙ | |||
2232 2233 2234 2235 2236 2237 2238 |
rbuf[p_ind] = 0;
rlen = strlen(rbuf);
}
continue;
}
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) {
| | | 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 |
rbuf[p_ind] = 0;
rlen = strlen(rbuf);
}
continue;
}
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) {
c = check_special(current);
}
#endif
if (c == ctrl('R')) {
/* Search for the previous (earlier) match */
if (searchpos > 0) {
searchpos--;
}
|
| ︙ | ︙ | |||
2344 2345 2346 2347 2348 2349 2350 |
/* reverse incremental search will provide an alternative keycode or 0 for none */
c = reverseIncrementalSearch(current);
/* go on to process the returned char normally */
}
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) { /* escape sequence */
| | | 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 |
/* reverse incremental search will provide an alternative keycode or 0 for none */
c = reverseIncrementalSearch(current);
/* go on to process the returned char normally */
}
#ifdef USE_TERMIOS
if (c == CHAR_ESCAPE) { /* escape sequence */
c = check_special(current);
}
#endif
if (c == -1) {
/* Return on errors */
return sb_len(current->buf);
}
|
| ︙ | ︙ |
Changes to extsrc/pikchr-worker.js.
| ︙ | ︙ | |||
34 35 36 37 38 39 40 |
{
pikchr: source code for the pikchr,
darkMode: boolean true to adjust colors for a dark color scheme,
cssClass: CSS class name to add to the SVG
}
| | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
{
pikchr: source code for the pikchr,
darkMode: boolean true to adjust colors for a dark color scheme,
cssClass: CSS class name to add to the SVG
}
Workers-to-Main message types:
- stdout, stderr: indicate stdout/stderr output from the wasm
layer. The data property is the string of the output, noting
that the emscripten binding emits these one line at a time. Thus,
if a C-side puts() emits multiple lines in a single call, the JS
side will see that as multiple calls. Example:
{type:'stdout', data: 'Hi, world.'}
- module: Status text. This is intended to alert the main thread
about module loading status so that, e.g., the main thread can
update a progress widget and DTRT when the module is finished
loading and available for work. Status messages come in the form
{type:'module', data:{
type:'status',
data: {text:string|null, step:1-based-integer}
}
with an incrementing step value for each subsequent message. When
the module loading is complete, a message with a text value of
null is posted.
- pikchr:
{type: 'pikchr',
data:{
pikchr: input text,
result: rendered result (SVG on success, HTML on error),
isError: bool, true if .pikchr holds an error report,
flags: integer: flags used to configure the pikchr rendering,
|
| ︙ | ︙ | |||
160 161 162 163 164 165 166 |
pikchrModule.stackRestore(stack);
wMsg('working','end');
}
return;
};
console.warn("Unknown pikchr-worker message type:",ev);
};
| | | 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
pikchrModule.stackRestore(stack);
wMsg('working','end');
}
return;
};
console.warn("Unknown pikchr-worker message type:",ev);
};
/**
emscripten module for use with build mode -sMODULARIZE.
*/
const pikchrModule = {
print: function(){wMsg('stdout', Array.prototype.slice.call(arguments));},
printErr: stderr,
/**
|
| ︙ | ︙ | |||
204 205 206 207 208 209 210 |
wMsg('module',{
type:'status',
data:{step: ++f.last.step, text: text||null}
});
}
};
| | > | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
wMsg('module',{
type:'status',
data:{step: ++f.last.step, text: text||null}
});
}
};
importScripts('pikchr-v2813665466.js');
/**
initPikchrModule() is installed via pikchr.js due to
building with:
emcc ... -sMODULARIZE=1 -sEXPORT_NAME=initPikchrModule
*/
initPikchrModule(pikchrModule).then(function(thisModule){
//globalThis.M = pikchrModule; console.warn("pikchrModule=globalThis.M=",globalThis.M);
wMsg('pikchr-ready', pikchrModule.ccall('pikchr_version','string'));
});
})();
|
Changes to extsrc/pikchr.c.
1 2 3 4 5 6 7 8 9 10 | /* This file is automatically generated by Lemon from input grammar ** source file "pikchr.y". */ /* ** Zero-Clause BSD license: ** ** Copyright (C) 2020-09-01 by D. Richard Hipp <drh@sqlite.org> ** ** Permission to use, copy, modify, and/or distribute this software for ** any purpose with or without fee is hereby granted. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* This file is automatically generated by Lemon from input grammar ** source file "pikchr.y". */ /* ** 2000-05-29 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Driver template for the LEMON parser generator. ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text ** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser ** source file. ** ** The following is the concatenation of all %include directives from the ** input grammar file: */ /************ Begin %include sections from the grammar ************************/ #line 1 "VERSION.h" #define MANIFEST_UUID "8a43b020141f772a0ac45291a7fd73041d2efba5e3665c6bd2f334ad9b2e9845" #define MANIFEST_VERSION "[8a43b02014]" #define MANIFEST_DATE "2025-03-19 16:19:43" #define MANIFEST_YEAR "2025" #define MANIFEST_ISODATE "20250319161943" #define MANIFEST_NUMERIC_DATE 20250319 #define MANIFEST_NUMERIC_TIME 161943 #define RELEASE_VERSION "1.0" #define RELEASE_VERSION_NUMBER 10000 #define RELEASE_RESOURCE_VERSION 1,0,0,0 #define COMPILER "gcc-13.3.0" #line 2 "pikchr.y" /* ** Zero-Clause BSD license: ** ** Copyright (C) 2020-09-01 by D. Richard Hipp <drh@sqlite.org> ** ** Permission to use, copy, modify, and/or distribute this software for ** any purpose with or without fee is hereby granted. |
| ︙ | ︙ | |||
123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #include <ctype.h> #include <math.h> #include <assert.h> #define count(X) (sizeof(X)/sizeof(X[0])) #ifndef M_PI # define M_PI 3.1415926535897932385 #endif /* Limit the number of tokens in a single script to avoid run-away ** macro expansion attacks. See forum post ** https://pikchr.org/home/forumpost/ef8684c6955a411a */ #ifndef PIKCHR_TOKEN_LIMIT # define PIKCHR_TOKEN_LIMIT 100000 | > > > > > > > > > > > > | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | #include <ctype.h> #include <math.h> #include <assert.h> #define count(X) (sizeof(X)/sizeof(X[0])) #ifndef M_PI # define M_PI 3.1415926535897932385 #endif /* ** Typesafe version of ctype.h macros. Cygwin requires this, I'm told. */ #define IsUpper(X) isupper((unsigned char)(X)) #define IsLower(X) islower((unsigned char)(X)) #define ToLower(X) tolower((unsigned char)(X)) #define IsDigit(X) isdigit((unsigned char)(X)) #define IsXDigit(X) isxdigit((unsigned char)(X)) #define IsSpace(X) isspace((unsigned char)(X)) #define IsAlnum(X) isalnum((unsigned char)(X)) /* Limit the number of tokens in a single script to avoid run-away ** macro expansion attacks. See forum post ** https://pikchr.org/home/forumpost/ef8684c6955a411a */ #ifndef PIKCHR_TOKEN_LIMIT # define PIKCHR_TOKEN_LIMIT 100000 |
| ︙ | ︙ | |||
472 473 474 475 476 477 478 | static int pik_bbox_contains_point(PBox*,PPoint*); static void pik_bbox_init(PBox*); static void pik_bbox_addbox(PBox*,PBox*); static void pik_bbox_add_xy(PBox*,PNum,PNum); static void pik_bbox_addellipse(PBox*,PNum x,PNum y,PNum rx,PNum ry); static void pik_add_txt(Pik*,PToken*,int); static int pik_text_length(const PToken *pToken, const int isMonospace); | | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | static int pik_bbox_contains_point(PBox*,PPoint*); static void pik_bbox_init(PBox*); static void pik_bbox_addbox(PBox*,PBox*); static void pik_bbox_add_xy(PBox*,PNum,PNum); static void pik_bbox_addellipse(PBox*,PNum x,PNum y,PNum rx,PNum ry); static void pik_add_txt(Pik*,PToken*,int); static int pik_text_length(const PToken *pToken, const int isMonospace); static void pik_size_to_fit(Pik*,PObj*,PToken*,int); static int pik_text_position(int,PToken*); static PNum pik_property_of(PObj*,PToken*); static PNum pik_func(Pik*,PToken*,PNum,PNum); static PPoint pik_position_between(PNum x, PPoint p1, PPoint p2); static PPoint pik_position_at_angle(PNum dist, PNum r, PPoint pt); static PPoint pik_position_at_hdg(PNum dist, PToken *pD, PPoint pt); static void pik_same(Pik *p, PObj*, PToken*); static PPoint pik_nth_vertex(Pik *p, PToken *pNth, PToken *pErr, PObj *pObj); static PToken pik_next_semantic_token(PToken *pThis); static void pik_compute_layout_settings(Pik*); static void pik_behind(Pik*,PObj*); static PObj *pik_assert(Pik*,PNum,PToken*,PNum); static PObj *pik_position_assert(Pik*,PPoint*,PToken*,PPoint*); static PNum pik_dist(PPoint*,PPoint*); static void pik_add_macro(Pik*,PToken *pId,PToken *pCode); #line 549 "pikchr.c" /**************** End of %include directives **********************************/ /* These constants specify the various numeric values for terminal symbols. ***************** Begin token definitions *************************************/ #ifndef T_ID #define T_ID 1 #define T_EDGEPT 2 #define T_OF 3 |
| ︙ | ︙ | |||
520 521 522 523 524 525 526 | #define T_CODEBLOCK 19 #define T_FILL 20 #define T_COLOR 21 #define T_THICKNESS 22 #define T_PRINT 23 #define T_STRING 24 #define T_COMMA 25 | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 | #define T_CODEBLOCK 19 #define T_FILL 20 #define T_COLOR 21 #define T_THICKNESS 22 #define T_PRINT 23 #define T_STRING 24 #define T_COMMA 25 #define T_ISODATE 26 #define T_CLASSNAME 27 #define T_LB 28 #define T_RB 29 #define T_UP 30 #define T_DOWN 31 #define T_LEFT 32 #define T_RIGHT 33 #define T_CLOSE 34 #define T_CHOP 35 #define T_FROM 36 #define T_TO 37 #define T_THEN 38 #define T_HEADING 39 #define T_GO 40 #define T_AT 41 #define T_WITH 42 #define T_SAME 43 #define T_AS 44 #define T_FIT 45 #define T_BEHIND 46 #define T_UNTIL 47 #define T_EVEN 48 #define T_DOT_E 49 #define T_HEIGHT 50 #define T_WIDTH 51 #define T_RADIUS 52 #define T_DIAMETER 53 #define T_DOTTED 54 #define T_DASHED 55 #define T_CW 56 #define T_CCW 57 #define T_LARROW 58 #define T_RARROW 59 #define T_LRARROW 60 #define T_INVIS 61 #define T_THICK 62 #define T_THIN 63 #define T_SOLID 64 #define T_CENTER 65 #define T_LJUST 66 #define T_RJUST 67 #define T_ABOVE 68 #define T_BELOW 69 #define T_ITALIC 70 #define T_BOLD 71 #define T_MONO 72 #define T_ALIGNED 73 #define T_BIG 74 #define T_SMALL 75 #define T_AND 76 #define T_LT 77 #define T_GT 78 #define T_ON 79 #define T_WAY 80 #define T_BETWEEN 81 #define T_THE 82 #define T_NTH 83 #define T_VERTEX 84 #define T_TOP 85 #define T_BOTTOM 86 #define T_START 87 #define T_END 88 #define T_IN 89 #define T_THIS 90 #define T_DOT_U 91 #define T_LAST 92 #define T_NUMBER 93 #define T_FUNC1 94 #define T_FUNC2 95 #define T_DIST 96 #define T_DOT_XY 97 #define T_X 98 #define T_Y 99 #define T_DOT_L 100 #endif /**************** End token definitions ***************************************/ /* The next sections is a series of control #defines. ** various aspects of the generated parser. ** YYCODETYPE is the data type used to store the integer codes ** that represent terminal and non-terminal symbols. |
| ︙ | ︙ | |||
658 659 660 661 662 663 664 | ** YY_MAX_DSTRCTR Maximum symbol value that has a destructor */ #ifndef INTERFACE # define INTERFACE 1 #endif /************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned char | | | < | | > > | < | 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 |
** YY_MAX_DSTRCTR Maximum symbol value that has a destructor
*/
#ifndef INTERFACE
# define INTERFACE 1
#endif
/************* Begin control #defines *****************************************/
#define YYCODETYPE unsigned char
#define YYNOCODE 138
#define YYACTIONTYPE unsigned short int
#define pik_parserTOKENTYPE PToken
typedef union {
int yyinit;
pik_parserTOKENTYPE yy0;
PList* yy23;
PRel yy28;
PObj* yy54;
PNum yy129;
PPoint yy187;
short int yy272;
} YYMINORTYPE;
#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
#endif
#define pik_parserARG_SDECL
#define pik_parserARG_PDECL
#define pik_parserARG_PARAM
|
| ︙ | ︙ | |||
691 692 693 694 695 696 697 | #define pik_parserCTX_PARAM ,p #define pik_parserCTX_FETCH Pik *p=yypParser->p; #define pik_parserCTX_STORE yypParser->p=p; #define YYFALLBACK 1 #define YYNSTATE 164 #define YYNRULE 156 #define YYNRULE_WITH_ACTION 116 | | | | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | #define pik_parserCTX_PARAM ,p #define pik_parserCTX_FETCH Pik *p=yypParser->p; #define pik_parserCTX_STORE yypParser->p=p; #define YYFALLBACK 1 #define YYNSTATE 164 #define YYNRULE 156 #define YYNRULE_WITH_ACTION 116 #define YYNTOKEN 101 #define YY_MAX_SHIFT 163 #define YY_MIN_SHIFTREDUCE 287 #define YY_MAX_SHIFTREDUCE 442 #define YY_ERROR_ACTION 443 #define YY_ACCEPT_ACTION 444 #define YY_NO_ACTION 445 #define YY_MIN_REDUCE 446 #define YY_MAX_REDUCE 601 #define YY_MIN_DSTRCTR 101 #define YY_MAX_DSTRCTR 104 /************* End control #defines *******************************************/ #define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0]))) /* Define the yytestcase() macro to be a no-op if is not already defined ** otherwise. ** ** Applications can choose to define yytestcase() in the %include section |
| ︙ | ︙ | |||
784 785 786 787 788 789 790 | ** yy_shift_ofst[] For each state, the offset into yy_action for ** shifting terminals. ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. ** *********** Begin parsing tables **********************************************/ | | | | | | | | | | | | | | | | | | | > > | < < | | | | | | | | | | > | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | | < | | | | | | | | | | | | | | | | | | | | < | < | | | < | | | | < | | | | > | | | | | | | | < | | | | | | > | | | | | > > > | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > | | < | | | | | > | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 |
** yy_shift_ofst[] For each state, the offset into yy_action for
** shifting terminals.
** yy_reduce_ofst[] For each state, the offset into yy_action for
** shifting non-terminals after a reduce.
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
#define YY_ACTTAB_COUNT (1305)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 575, 495, 161, 119, 25, 452, 29, 74, 129, 148,
/* 10 */ 575, 64, 63, 62, 61, 453, 113, 120, 161, 119,
/* 20 */ 427, 428, 339, 357, 81, 121, 447, 454, 29, 575,
/* 30 */ 530, 13, 50, 450, 322, 323, 9, 8, 33, 149,
/* 40 */ 32, 7, 71, 127, 163, 335, 66, 28, 444, 27,
/* 50 */ 339, 339, 339, 339, 425, 426, 340, 341, 342, 343,
/* 60 */ 344, 345, 346, 347, 348, 474, 64, 63, 62, 61,
/* 70 */ 54, 51, 73, 306, 148, 474, 492, 161, 119, 297,
/* 80 */ 112, 113, 120, 161, 119, 427, 428, 339, 30, 81,
/* 90 */ 109, 447, 454, 29, 474, 528, 161, 119, 450, 322,
/* 100 */ 323, 9, 8, 33, 149, 32, 7, 71, 127, 163,
/* 110 */ 335, 66, 535, 36, 27, 339, 339, 339, 339, 425,
/* 120 */ 426, 340, 341, 342, 343, 344, 345, 346, 347, 348,
/* 130 */ 394, 435, 310, 59, 60, 64, 63, 62, 61, 313,
/* 140 */ 74, 376, 148, 69, 2, 533, 161, 119, 124, 113,
/* 150 */ 120, 161, 119, 80, 535, 31, 308, 79, 83, 107,
/* 160 */ 535, 441, 440, 535, 394, 435, 299, 59, 60, 120,
/* 170 */ 161, 119, 149, 463, 376, 376, 330, 84, 2, 122,
/* 180 */ 78, 78, 38, 156, 156, 156, 48, 37, 559, 328,
/* 190 */ 128, 152, 560, 561, 434, 441, 440, 350, 350, 350,
/* 200 */ 350, 350, 350, 350, 350, 350, 350, 350, 577, 77,
/* 210 */ 577, 35, 106, 46, 436, 437, 438, 439, 579, 375,
/* 220 */ 298, 117, 393, 155, 154, 153, 47, 4, 434, 69,
/* 230 */ 394, 435, 3, 59, 60, 411, 412, 413, 414, 398,
/* 240 */ 399, 376, 62, 61, 2, 108, 106, 5, 436, 437,
/* 250 */ 438, 439, 375, 375, 117, 117, 393, 155, 154, 153,
/* 260 */ 76, 441, 440, 67, 6, 142, 140, 64, 63, 62,
/* 270 */ 61, 380, 157, 424, 427, 428, 339, 379, 159, 45,
/* 280 */ 423, 72, 131, 148, 531, 161, 119, 1, 55, 125,
/* 290 */ 113, 120, 161, 119, 434, 147, 146, 64, 63, 62,
/* 300 */ 61, 397, 43, 11, 339, 339, 339, 339, 425, 426,
/* 310 */ 355, 65, 106, 149, 436, 437, 438, 439, 74, 375,
/* 320 */ 148, 117, 393, 155, 154, 153, 497, 113, 120, 161,
/* 330 */ 119, 22, 21, 12, 142, 140, 64, 63, 62, 61,
/* 340 */ 24, 356, 145, 141, 431, 64, 63, 62, 61, 391,
/* 350 */ 149, 448, 454, 29, 378, 158, 85, 55, 450, 394,
/* 360 */ 432, 138, 59, 60, 147, 146, 120, 161, 119, 163,
/* 370 */ 102, 43, 139, 42, 27, 430, 14, 15, 301, 302,
/* 380 */ 303, 446, 305, 16, 44, 74, 18, 148, 152, 19,
/* 390 */ 20, 36, 68, 496, 113, 120, 161, 119, 114, 359,
/* 400 */ 22, 21, 23, 142, 140, 64, 63, 62, 61, 24,
/* 410 */ 107, 145, 141, 431, 26, 57, 377, 149, 58, 118,
/* 420 */ 120, 161, 119, 392, 463, 384, 55, 64, 63, 62,
/* 430 */ 61, 382, 569, 147, 146, 160, 383, 435, 39, 70,
/* 440 */ 43, 106, 152, 445, 445, 88, 445, 445, 375, 445,
/* 450 */ 117, 393, 155, 154, 153, 120, 161, 119, 445, 17,
/* 460 */ 445, 10, 479, 479, 445, 445, 435, 441, 440, 22,
/* 470 */ 21, 445, 403, 64, 63, 62, 61, 152, 24, 445,
/* 480 */ 145, 141, 431, 133, 75, 126, 354, 445, 445, 123,
/* 490 */ 445, 404, 405, 406, 408, 80, 441, 440, 308, 79,
/* 500 */ 434, 411, 412, 413, 414, 394, 445, 445, 59, 60,
/* 510 */ 64, 63, 62, 61, 445, 445, 376, 445, 445, 42,
/* 520 */ 436, 437, 438, 439, 156, 156, 156, 394, 445, 434,
/* 530 */ 59, 60, 64, 63, 62, 61, 445, 445, 376, 445,
/* 540 */ 445, 42, 445, 394, 473, 391, 59, 60, 445, 436,
/* 550 */ 437, 438, 439, 49, 376, 445, 74, 42, 148, 445,
/* 560 */ 88, 445, 445, 445, 490, 113, 120, 161, 119, 445,
/* 570 */ 120, 161, 119, 132, 130, 394, 143, 475, 59, 60,
/* 580 */ 445, 473, 64, 63, 62, 61, 376, 106, 149, 42,
/* 590 */ 445, 445, 152, 445, 375, 391, 117, 393, 155, 154,
/* 600 */ 153, 394, 144, 52, 59, 60, 445, 445, 445, 106,
/* 610 */ 445, 445, 376, 445, 445, 42, 375, 445, 117, 393,
/* 620 */ 155, 154, 153, 445, 445, 106, 64, 63, 62, 61,
/* 630 */ 445, 445, 375, 445, 117, 393, 155, 154, 153, 394,
/* 640 */ 445, 445, 59, 60, 88, 445, 445, 53, 445, 445,
/* 650 */ 376, 445, 445, 42, 120, 161, 119, 106, 445, 445,
/* 660 */ 445, 110, 110, 445, 375, 445, 117, 393, 155, 154,
/* 670 */ 153, 394, 445, 445, 59, 60, 152, 107, 445, 445,
/* 680 */ 445, 445, 102, 106, 445, 42, 445, 120, 161, 119,
/* 690 */ 375, 451, 117, 393, 155, 154, 153, 394, 445, 445,
/* 700 */ 59, 60, 64, 63, 62, 61, 445, 445, 376, 152,
/* 710 */ 445, 40, 445, 394, 445, 396, 59, 60, 445, 445,
/* 720 */ 445, 106, 445, 445, 376, 88, 445, 41, 375, 445,
/* 730 */ 117, 393, 155, 154, 153, 120, 161, 119, 74, 445,
/* 740 */ 148, 445, 111, 111, 107, 445, 484, 113, 120, 161,
/* 750 */ 119, 445, 445, 106, 120, 161, 119, 152, 478, 445,
/* 760 */ 375, 86, 117, 393, 155, 154, 153, 445, 445, 445,
/* 770 */ 149, 120, 161, 119, 445, 445, 152, 445, 445, 106,
/* 780 */ 445, 64, 63, 62, 61, 445, 375, 445, 117, 393,
/* 790 */ 155, 154, 153, 152, 395, 106, 64, 63, 62, 61,
/* 800 */ 98, 445, 375, 445, 117, 393, 155, 154, 153, 445,
/* 810 */ 120, 161, 119, 445, 74, 445, 148, 56, 445, 74,
/* 820 */ 445, 148, 483, 113, 120, 161, 119, 480, 113, 120,
/* 830 */ 161, 119, 152, 74, 445, 148, 445, 89, 445, 445,
/* 840 */ 445, 134, 113, 120, 161, 119, 149, 120, 161, 119,
/* 850 */ 445, 149, 74, 445, 148, 445, 445, 445, 378, 158,
/* 860 */ 517, 113, 120, 161, 119, 149, 74, 445, 148, 152,
/* 870 */ 445, 74, 445, 148, 137, 113, 120, 161, 119, 525,
/* 880 */ 113, 120, 161, 119, 149, 74, 445, 148, 64, 63,
/* 890 */ 62, 61, 445, 527, 113, 120, 161, 119, 149, 445,
/* 900 */ 445, 391, 445, 149, 445, 445, 445, 445, 445, 445,
/* 910 */ 74, 445, 148, 445, 445, 162, 445, 149, 524, 113,
/* 920 */ 120, 161, 119, 118, 445, 74, 445, 148, 445, 445,
/* 930 */ 445, 445, 445, 526, 113, 120, 161, 119, 445, 74,
/* 940 */ 445, 148, 149, 445, 445, 445, 445, 523, 113, 120,
/* 950 */ 161, 119, 74, 445, 148, 445, 445, 149, 445, 445,
/* 960 */ 522, 113, 120, 161, 119, 445, 74, 445, 148, 445,
/* 970 */ 445, 149, 445, 445, 521, 113, 120, 161, 119, 74,
/* 980 */ 445, 148, 445, 445, 149, 445, 445, 520, 113, 120,
/* 990 */ 161, 119, 445, 74, 445, 148, 445, 445, 149, 445,
/* 1000 */ 445, 519, 113, 120, 161, 119, 445, 445, 445, 445,
/* 1010 */ 445, 149, 445, 445, 445, 445, 445, 445, 74, 445,
/* 1020 */ 148, 445, 445, 445, 445, 149, 150, 113, 120, 161,
/* 1030 */ 119, 74, 445, 148, 445, 445, 445, 445, 445, 151,
/* 1040 */ 113, 120, 161, 119, 445, 74, 445, 148, 445, 445,
/* 1050 */ 149, 445, 445, 136, 113, 120, 161, 119, 74, 445,
/* 1060 */ 148, 445, 445, 149, 445, 445, 135, 113, 120, 161,
/* 1070 */ 119, 445, 88, 445, 445, 445, 445, 149, 445, 445,
/* 1080 */ 445, 90, 120, 161, 119, 445, 445, 445, 445, 82,
/* 1090 */ 149, 120, 161, 119, 445, 87, 466, 445, 34, 99,
/* 1100 */ 445, 445, 445, 445, 152, 120, 161, 119, 100, 120,
/* 1110 */ 161, 119, 445, 152, 445, 445, 445, 445, 120, 161,
/* 1120 */ 119, 445, 445, 445, 101, 445, 445, 152, 445, 445,
/* 1130 */ 445, 152, 91, 445, 120, 161, 119, 103, 445, 445,
/* 1140 */ 152, 445, 120, 161, 119, 445, 445, 120, 161, 119,
/* 1150 */ 445, 92, 445, 445, 445, 445, 152, 445, 445, 445,
/* 1160 */ 93, 120, 161, 119, 152, 445, 104, 445, 445, 152,
/* 1170 */ 120, 161, 119, 445, 94, 445, 120, 161, 119, 445,
/* 1180 */ 445, 445, 445, 152, 120, 161, 119, 445, 445, 105,
/* 1190 */ 445, 445, 152, 445, 445, 445, 445, 95, 152, 120,
/* 1200 */ 161, 119, 96, 445, 445, 97, 152, 120, 161, 119,
/* 1210 */ 445, 445, 120, 161, 119, 120, 161, 119, 445, 445,
/* 1220 */ 445, 152, 445, 445, 445, 445, 445, 445, 445, 152,
/* 1230 */ 549, 445, 445, 548, 152, 445, 445, 152, 547, 445,
/* 1240 */ 120, 161, 119, 120, 161, 119, 546, 445, 120, 161,
/* 1250 */ 119, 445, 445, 445, 445, 445, 120, 161, 119, 445,
/* 1260 */ 445, 445, 152, 445, 445, 152, 445, 445, 445, 115,
/* 1270 */ 152, 445, 116, 445, 445, 445, 445, 445, 152, 120,
/* 1280 */ 161, 119, 120, 161, 119, 445, 445, 445, 445, 445,
/* 1290 */ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445,
/* 1300 */ 445, 152, 445, 445, 152,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 0, 115, 116, 117, 136, 103, 104, 105, 107, 107,
/* 10 */ 10, 4, 5, 6, 7, 113, 114, 115, 116, 117,
/* 20 */ 20, 21, 22, 17, 24, 101, 102, 103, 104, 29,
/* 30 */ 107, 25, 25, 109, 34, 35, 36, 37, 38, 137,
/* 40 */ 40, 41, 42, 43, 120, 45, 46, 109, 124, 125,
/* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
/* 60 */ 60, 61, 62, 63, 64, 0, 4, 5, 6, 7,
/* 70 */ 4, 5, 105, 25, 107, 10, 115, 116, 117, 17,
/* 80 */ 113, 114, 115, 116, 117, 20, 21, 22, 128, 24,
/* 90 */ 101, 102, 103, 104, 29, 115, 116, 117, 109, 34,
/* 100 */ 35, 36, 37, 38, 137, 40, 41, 42, 43, 120,
/* 110 */ 45, 46, 49, 10, 125, 50, 51, 52, 53, 54,
/* 120 */ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
/* 130 */ 1, 2, 29, 4, 5, 4, 5, 6, 7, 8,
/* 140 */ 105, 12, 107, 3, 15, 115, 116, 117, 113, 114,
/* 150 */ 115, 116, 117, 24, 91, 130, 27, 28, 118, 105,
/* 160 */ 97, 32, 33, 100, 1, 2, 19, 4, 5, 115,
/* 170 */ 116, 117, 137, 119, 12, 12, 2, 118, 15, 1,
/* 180 */ 126, 127, 106, 20, 21, 22, 110, 111, 106, 2,
/* 190 */ 107, 137, 110, 111, 65, 32, 33, 65, 66, 67,
/* 200 */ 68, 69, 70, 71, 72, 73, 74, 75, 132, 133,
/* 210 */ 134, 131, 83, 39, 85, 86, 87, 88, 135, 90,
/* 220 */ 17, 92, 93, 94, 95, 96, 39, 15, 65, 89,
/* 230 */ 1, 2, 16, 4, 5, 30, 31, 32, 33, 98,
/* 240 */ 99, 12, 6, 7, 15, 83, 83, 41, 85, 86,
/* 250 */ 87, 88, 90, 90, 92, 92, 93, 94, 95, 96,
/* 260 */ 49, 32, 33, 44, 41, 2, 3, 4, 5, 6,
/* 270 */ 7, 27, 28, 42, 20, 21, 22, 27, 28, 16,
/* 280 */ 42, 105, 48, 107, 115, 116, 117, 13, 25, 113,
/* 290 */ 114, 115, 116, 117, 65, 32, 33, 4, 5, 6,
/* 300 */ 7, 17, 39, 25, 50, 51, 52, 53, 54, 55,
/* 310 */ 17, 100, 83, 137, 85, 86, 87, 88, 105, 90,
/* 320 */ 107, 92, 93, 94, 95, 96, 113, 114, 115, 116,
/* 330 */ 117, 68, 69, 76, 2, 3, 4, 5, 6, 7,
/* 340 */ 77, 17, 79, 80, 81, 4, 5, 6, 7, 17,
/* 350 */ 137, 102, 103, 104, 27, 28, 105, 25, 109, 1,
/* 360 */ 81, 80, 4, 5, 32, 33, 115, 116, 117, 120,
/* 370 */ 12, 39, 82, 15, 125, 81, 3, 36, 20, 21,
/* 380 */ 22, 0, 24, 3, 39, 105, 3, 107, 137, 3,
/* 390 */ 3, 10, 3, 113, 114, 115, 116, 117, 97, 78,
/* 400 */ 68, 69, 25, 2, 3, 4, 5, 6, 7, 77,
/* 410 */ 105, 79, 80, 81, 15, 15, 12, 137, 15, 92,
/* 420 */ 115, 116, 117, 17, 119, 29, 25, 4, 5, 6,
/* 430 */ 7, 29, 127, 32, 33, 91, 29, 2, 11, 3,
/* 440 */ 39, 83, 137, 138, 138, 105, 138, 138, 90, 138,
/* 450 */ 92, 93, 94, 95, 96, 115, 116, 117, 138, 36,
/* 460 */ 138, 121, 122, 123, 138, 138, 2, 32, 33, 68,
/* 470 */ 69, 138, 1, 4, 5, 6, 7, 137, 77, 138,
/* 480 */ 79, 80, 81, 12, 49, 14, 17, 138, 138, 18,
/* 490 */ 138, 20, 21, 22, 23, 24, 32, 33, 27, 28,
/* 500 */ 65, 30, 31, 32, 33, 1, 138, 138, 4, 5,
/* 510 */ 4, 5, 6, 7, 138, 138, 12, 138, 138, 15,
/* 520 */ 85, 86, 87, 88, 20, 21, 22, 1, 138, 65,
/* 530 */ 4, 5, 4, 5, 6, 7, 138, 138, 12, 138,
/* 540 */ 138, 15, 138, 1, 2, 17, 4, 5, 138, 85,
/* 550 */ 86, 87, 88, 25, 12, 138, 105, 15, 107, 138,
/* 560 */ 105, 138, 138, 138, 113, 114, 115, 116, 117, 138,
/* 570 */ 115, 116, 117, 47, 48, 1, 2, 122, 4, 5,
/* 580 */ 138, 39, 4, 5, 6, 7, 12, 83, 137, 15,
/* 590 */ 138, 138, 137, 138, 90, 17, 92, 93, 94, 95,
/* 600 */ 96, 1, 2, 25, 4, 5, 138, 138, 138, 83,
/* 610 */ 138, 138, 12, 138, 138, 15, 90, 138, 92, 93,
/* 620 */ 94, 95, 96, 138, 138, 83, 4, 5, 6, 7,
/* 630 */ 138, 138, 90, 138, 92, 93, 94, 95, 96, 1,
/* 640 */ 138, 138, 4, 5, 105, 138, 138, 25, 138, 138,
/* 650 */ 12, 138, 138, 15, 115, 116, 117, 83, 138, 138,
/* 660 */ 138, 122, 123, 138, 90, 138, 92, 93, 94, 95,
/* 670 */ 96, 1, 138, 138, 4, 5, 137, 105, 138, 138,
/* 680 */ 138, 138, 12, 83, 138, 15, 138, 115, 116, 117,
/* 690 */ 90, 119, 92, 93, 94, 95, 96, 1, 138, 138,
/* 700 */ 4, 5, 4, 5, 6, 7, 138, 138, 12, 137,
/* 710 */ 138, 15, 138, 1, 138, 17, 4, 5, 138, 138,
/* 720 */ 138, 83, 138, 138, 12, 105, 138, 15, 90, 138,
/* 730 */ 92, 93, 94, 95, 96, 115, 116, 117, 105, 138,
/* 740 */ 107, 138, 122, 123, 105, 138, 113, 114, 115, 116,
/* 750 */ 117, 138, 138, 83, 115, 116, 117, 137, 119, 138,
/* 760 */ 90, 105, 92, 93, 94, 95, 96, 138, 138, 138,
/* 770 */ 137, 115, 116, 117, 138, 138, 137, 138, 138, 83,
/* 780 */ 138, 4, 5, 6, 7, 138, 90, 138, 92, 93,
/* 790 */ 94, 95, 96, 137, 17, 83, 4, 5, 6, 7,
/* 800 */ 105, 138, 90, 138, 92, 93, 94, 95, 96, 138,
/* 810 */ 115, 116, 117, 138, 105, 138, 107, 25, 138, 105,
/* 820 */ 138, 107, 113, 114, 115, 116, 117, 113, 114, 115,
/* 830 */ 116, 117, 137, 105, 138, 107, 138, 105, 138, 138,
/* 840 */ 138, 113, 114, 115, 116, 117, 137, 115, 116, 117,
/* 850 */ 138, 137, 105, 138, 107, 138, 138, 138, 27, 28,
/* 860 */ 113, 114, 115, 116, 117, 137, 105, 138, 107, 137,
/* 870 */ 138, 105, 138, 107, 113, 114, 115, 116, 117, 113,
/* 880 */ 114, 115, 116, 117, 137, 105, 138, 107, 4, 5,
/* 890 */ 6, 7, 138, 113, 114, 115, 116, 117, 137, 138,
/* 900 */ 138, 17, 138, 137, 138, 138, 138, 138, 138, 138,
/* 910 */ 105, 138, 107, 138, 138, 84, 138, 137, 113, 114,
/* 920 */ 115, 116, 117, 92, 138, 105, 138, 107, 138, 138,
/* 930 */ 138, 138, 138, 113, 114, 115, 116, 117, 138, 105,
/* 940 */ 138, 107, 137, 138, 138, 138, 138, 113, 114, 115,
/* 950 */ 116, 117, 105, 138, 107, 138, 138, 137, 138, 138,
/* 960 */ 113, 114, 115, 116, 117, 138, 105, 138, 107, 138,
/* 970 */ 138, 137, 138, 138, 113, 114, 115, 116, 117, 105,
/* 980 */ 138, 107, 138, 138, 137, 138, 138, 113, 114, 115,
/* 990 */ 116, 117, 138, 105, 138, 107, 138, 138, 137, 138,
/* 1000 */ 138, 113, 114, 115, 116, 117, 138, 138, 138, 138,
/* 1010 */ 138, 137, 138, 138, 138, 138, 138, 138, 105, 138,
/* 1020 */ 107, 138, 138, 138, 138, 137, 113, 114, 115, 116,
/* 1030 */ 117, 105, 138, 107, 138, 138, 138, 138, 138, 113,
/* 1040 */ 114, 115, 116, 117, 138, 105, 138, 107, 138, 138,
/* 1050 */ 137, 138, 138, 113, 114, 115, 116, 117, 105, 138,
/* 1060 */ 107, 138, 138, 137, 138, 138, 113, 114, 115, 116,
/* 1070 */ 117, 138, 105, 138, 138, 138, 138, 137, 138, 138,
/* 1080 */ 138, 105, 115, 116, 117, 138, 138, 138, 138, 122,
/* 1090 */ 137, 115, 116, 117, 138, 105, 129, 138, 131, 105,
/* 1100 */ 138, 138, 138, 138, 137, 115, 116, 117, 105, 115,
/* 1110 */ 116, 117, 138, 137, 138, 138, 138, 138, 115, 116,
/* 1120 */ 117, 138, 138, 138, 105, 138, 138, 137, 138, 138,
/* 1130 */ 138, 137, 105, 138, 115, 116, 117, 105, 138, 138,
/* 1140 */ 137, 138, 115, 116, 117, 138, 138, 115, 116, 117,
/* 1150 */ 138, 105, 138, 138, 138, 138, 137, 138, 138, 138,
/* 1160 */ 105, 115, 116, 117, 137, 138, 105, 138, 138, 137,
/* 1170 */ 115, 116, 117, 138, 105, 138, 115, 116, 117, 138,
/* 1180 */ 138, 138, 138, 137, 115, 116, 117, 138, 138, 105,
/* 1190 */ 138, 138, 137, 138, 138, 138, 138, 105, 137, 115,
/* 1200 */ 116, 117, 105, 138, 138, 105, 137, 115, 116, 117,
/* 1210 */ 138, 138, 115, 116, 117, 115, 116, 117, 138, 138,
/* 1220 */ 138, 137, 138, 138, 138, 138, 138, 138, 138, 137,
/* 1230 */ 105, 138, 138, 105, 137, 138, 138, 137, 105, 138,
/* 1240 */ 115, 116, 117, 115, 116, 117, 105, 138, 115, 116,
/* 1250 */ 117, 138, 138, 138, 138, 138, 115, 116, 117, 138,
/* 1260 */ 138, 138, 137, 138, 138, 137, 138, 138, 138, 105,
/* 1270 */ 137, 138, 105, 138, 138, 138, 138, 138, 137, 115,
/* 1280 */ 116, 117, 115, 116, 117, 138, 138, 138, 138, 138,
/* 1290 */ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
/* 1300 */ 138, 137, 138, 138, 137, 101, 101, 101, 101, 101,
/* 1310 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1320 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1330 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1340 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1350 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1360 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1370 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1380 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1390 */ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
/* 1400 */ 101, 101, 101, 101, 101, 101,
};
#define YY_SHIFT_COUNT (163)
#define YY_SHIFT_MIN (0)
#define YY_SHIFT_MAX (884)
static const unsigned short int yy_shift_ofst[] = {
/* 0 */ 471, 129, 163, 229, 229, 229, 229, 229, 229, 229,
/* 10 */ 229, 229, 229, 229, 229, 229, 229, 229, 229, 229,
/* 20 */ 229, 229, 229, 229, 229, 229, 229, 358, 526, 638,
/* 30 */ 358, 471, 542, 542, 0, 65, 471, 670, 638, 670,
/* 40 */ 504, 504, 504, 574, 600, 638, 638, 638, 638, 638,
/* 50 */ 638, 696, 638, 638, 712, 638, 638, 638, 638, 638,
/* 60 */ 638, 638, 638, 638, 638, 254, 162, 162, 162, 162,
/* 70 */ 162, 435, 263, 332, 401, 464, 464, 205, 48, 1305,
/* 80 */ 1305, 1305, 1305, 132, 132, 528, 578, 62, 131, 341,
/* 90 */ 423, 293, 7, 469, 622, 698, 792, 777, 884, 506,
/* 100 */ 506, 506, 63, 506, 506, 506, 831, 506, 327, 103,
/* 110 */ 174, 187, 6, 66, 141, 236, 236, 244, 250, 140,
/* 120 */ 211, 381, 147, 178, 203, 216, 212, 219, 206, 223,
/* 130 */ 231, 238, 234, 274, 284, 278, 257, 324, 279, 281,
/* 140 */ 290, 294, 373, 380, 383, 345, 386, 387, 389, 301,
/* 150 */ 321, 377, 301, 399, 400, 403, 406, 396, 402, 407,
/* 160 */ 404, 344, 436, 427,
};
#define YY_REDUCE_COUNT (82)
#define YY_REDUCE_MIN (-132)
#define YY_REDUCE_MAX (1167)
static const short yy_reduce_ofst[] = {
/* 0 */ -76, -98, -33, 35, 176, 213, 280, 451, 633, 709,
/* 10 */ 714, 728, 747, 761, 766, 780, 805, 820, 834, 847,
/* 20 */ 861, 874, 888, 913, 926, 940, 953, 54, 340, 967,
/* 30 */ 305, -11, 539, 620, 76, 76, 249, 639, 455, 572,
/* 40 */ 251, 656, 695, 732, 976, 990, 994, 1003, 1019, 1027,
/* 50 */ 1032, 1046, 1055, 1061, 1069, 1084, 1092, 1097, 1100, 1125,
/* 60 */ 1128, 1133, 1141, 1164, 1167, 82, -114, -39, -20, 30,
/* 70 */ 169, 83, -132, -132, -132, -99, -77, -62, -40, 25,
/* 80 */ 40, 59, 80,
};
static const YYACTIONTYPE yy_default[] = {
/* 0 */ 449, 443, 443, 443, 443, 443, 443, 443, 443, 443,
/* 10 */ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443,
/* 20 */ 443, 443, 443, 443, 443, 443, 443, 443, 473, 576,
/* 30 */ 443, 449, 580, 485, 581, 581, 449, 443, 443, 443,
/* 40 */ 443, 443, 443, 443, 443, 443, 443, 443, 477, 443,
|
| ︙ | ︙ | |||
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 |
0, /* CODEBLOCK => nothing */
0, /* FILL => nothing */
0, /* COLOR => nothing */
0, /* THICKNESS => nothing */
0, /* PRINT => nothing */
0, /* STRING => nothing */
0, /* COMMA => nothing */
0, /* CLASSNAME => nothing */
0, /* LB => nothing */
0, /* RB => nothing */
0, /* UP => nothing */
0, /* DOWN => nothing */
0, /* LEFT => nothing */
0, /* RIGHT => nothing */
| > | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 |
0, /* CODEBLOCK => nothing */
0, /* FILL => nothing */
0, /* COLOR => nothing */
0, /* THICKNESS => nothing */
0, /* PRINT => nothing */
0, /* STRING => nothing */
0, /* COMMA => nothing */
0, /* ISODATE => nothing */
0, /* CLASSNAME => nothing */
0, /* LB => nothing */
0, /* RB => nothing */
0, /* UP => nothing */
0, /* DOWN => nothing */
0, /* LEFT => nothing */
0, /* RIGHT => nothing */
|
| ︙ | ︙ | |||
1345 1346 1347 1348 1349 1350 1351 | /* 19 */ "CODEBLOCK", /* 20 */ "FILL", /* 21 */ "COLOR", /* 22 */ "THICKNESS", /* 23 */ "PRINT", /* 24 */ "STRING", /* 25 */ "COMMA", | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > | < < | | | | | | | | | | | | | | | | | | | | | | | | | > > | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 |
/* 19 */ "CODEBLOCK",
/* 20 */ "FILL",
/* 21 */ "COLOR",
/* 22 */ "THICKNESS",
/* 23 */ "PRINT",
/* 24 */ "STRING",
/* 25 */ "COMMA",
/* 26 */ "ISODATE",
/* 27 */ "CLASSNAME",
/* 28 */ "LB",
/* 29 */ "RB",
/* 30 */ "UP",
/* 31 */ "DOWN",
/* 32 */ "LEFT",
/* 33 */ "RIGHT",
/* 34 */ "CLOSE",
/* 35 */ "CHOP",
/* 36 */ "FROM",
/* 37 */ "TO",
/* 38 */ "THEN",
/* 39 */ "HEADING",
/* 40 */ "GO",
/* 41 */ "AT",
/* 42 */ "WITH",
/* 43 */ "SAME",
/* 44 */ "AS",
/* 45 */ "FIT",
/* 46 */ "BEHIND",
/* 47 */ "UNTIL",
/* 48 */ "EVEN",
/* 49 */ "DOT_E",
/* 50 */ "HEIGHT",
/* 51 */ "WIDTH",
/* 52 */ "RADIUS",
/* 53 */ "DIAMETER",
/* 54 */ "DOTTED",
/* 55 */ "DASHED",
/* 56 */ "CW",
/* 57 */ "CCW",
/* 58 */ "LARROW",
/* 59 */ "RARROW",
/* 60 */ "LRARROW",
/* 61 */ "INVIS",
/* 62 */ "THICK",
/* 63 */ "THIN",
/* 64 */ "SOLID",
/* 65 */ "CENTER",
/* 66 */ "LJUST",
/* 67 */ "RJUST",
/* 68 */ "ABOVE",
/* 69 */ "BELOW",
/* 70 */ "ITALIC",
/* 71 */ "BOLD",
/* 72 */ "MONO",
/* 73 */ "ALIGNED",
/* 74 */ "BIG",
/* 75 */ "SMALL",
/* 76 */ "AND",
/* 77 */ "LT",
/* 78 */ "GT",
/* 79 */ "ON",
/* 80 */ "WAY",
/* 81 */ "BETWEEN",
/* 82 */ "THE",
/* 83 */ "NTH",
/* 84 */ "VERTEX",
/* 85 */ "TOP",
/* 86 */ "BOTTOM",
/* 87 */ "START",
/* 88 */ "END",
/* 89 */ "IN",
/* 90 */ "THIS",
/* 91 */ "DOT_U",
/* 92 */ "LAST",
/* 93 */ "NUMBER",
/* 94 */ "FUNC1",
/* 95 */ "FUNC2",
/* 96 */ "DIST",
/* 97 */ "DOT_XY",
/* 98 */ "X",
/* 99 */ "Y",
/* 100 */ "DOT_L",
/* 101 */ "statement_list",
/* 102 */ "statement",
/* 103 */ "unnamed_statement",
/* 104 */ "basetype",
/* 105 */ "expr",
/* 106 */ "numproperty",
/* 107 */ "edge",
/* 108 */ "isodate",
/* 109 */ "direction",
/* 110 */ "dashproperty",
/* 111 */ "colorproperty",
/* 112 */ "locproperty",
/* 113 */ "position",
/* 114 */ "place",
/* 115 */ "object",
/* 116 */ "objectname",
/* 117 */ "nth",
/* 118 */ "textposition",
/* 119 */ "rvalue",
/* 120 */ "lvalue",
/* 121 */ "even",
/* 122 */ "relexpr",
/* 123 */ "optrelexpr",
/* 124 */ "document",
/* 125 */ "print",
/* 126 */ "prlist",
/* 127 */ "pritem",
/* 128 */ "prsep",
/* 129 */ "attribute_list",
/* 130 */ "savelist",
/* 131 */ "alist",
/* 132 */ "attribute",
/* 133 */ "go",
/* 134 */ "boolproperty",
/* 135 */ "withclause",
/* 136 */ "between",
/* 137 */ "place2",
};
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
#ifndef NDEBUG
/* For tracing reduce actions, the names of all rules are required.
*/
static const char *const yyRuleName[] = {
|
| ︙ | ︙ | |||
1741 1742 1743 1744 1745 1746 1747 |
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are *not* used
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
| | | | | | | | | | | | 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 |
** being destroyed before it is finished parsing.
**
** Note: during a reduce, the only symbols destroyed are those
** which appear on the RHS of the rule, but which are *not* used
** inside the C code.
*/
/********* Begin destructor definitions ***************************************/
case 101: /* statement_list */
{
#line 524 "pikchr.y"
pik_elist_free(p,(yypminor->yy23));
#line 1805 "pikchr.c"
}
break;
case 102: /* statement */
case 103: /* unnamed_statement */
case 104: /* basetype */
{
#line 526 "pikchr.y"
pik_elem_free(p,(yypminor->yy54));
#line 1814 "pikchr.c"
}
break;
/********* End destructor definitions *****************************************/
default: break; /* If no destructor action specified: do nothing */
}
}
|
| ︙ | ︙ | |||
1989 1990 1991 1992 1993 1994 1995 |
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
}
#endif
while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
| | | | 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
}
#endif
while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
/* Here code is inserted which will execute if the parser
** stack every overflows */
/******** Begin %stack_overflow code ******************************************/
#line 559 "pikchr.y"
pik_error(p, 0, "parser stack overflow");
#line 2052 "pikchr.c"
/******** End %stack_overflow code ********************************************/
pik_parserARG_STORE /* Suppress warning about unused %extra_argument var */
pik_parserCTX_STORE
}
/*
** Print tracing information for a SHIFT action
|
| ︙ | ︙ | |||
2058 2059 2060 2061 2062 2063 2064 |
yytos->minor.yy0 = yyMinor;
yyTraceShift(yypParser, yyNewState, "Shift");
}
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 |
yytos->minor.yy0 = yyMinor;
yyTraceShift(yypParser, yyNewState, "Shift");
}
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
** of that rule */
static const YYCODETYPE yyRuleInfoLhs[] = {
124, /* (0) document ::= statement_list */
101, /* (1) statement_list ::= statement */
101, /* (2) statement_list ::= statement_list EOL statement */
102, /* (3) statement ::= */
102, /* (4) statement ::= direction */
102, /* (5) statement ::= lvalue ASSIGN rvalue */
102, /* (6) statement ::= PLACENAME COLON unnamed_statement */
102, /* (7) statement ::= PLACENAME COLON position */
102, /* (8) statement ::= unnamed_statement */
102, /* (9) statement ::= print prlist */
102, /* (10) statement ::= ASSERT LP expr EQ expr RP */
102, /* (11) statement ::= ASSERT LP position EQ position RP */
102, /* (12) statement ::= DEFINE ID CODEBLOCK */
119, /* (13) rvalue ::= PLACENAME */
127, /* (14) pritem ::= FILL */
127, /* (15) pritem ::= COLOR */
127, /* (16) pritem ::= THICKNESS */
127, /* (17) pritem ::= rvalue */
127, /* (18) pritem ::= STRING */
128, /* (19) prsep ::= COMMA */
103, /* (20) unnamed_statement ::= basetype attribute_list */
104, /* (21) basetype ::= CLASSNAME */
104, /* (22) basetype ::= STRING textposition */
104, /* (23) basetype ::= LB savelist statement_list RB */
130, /* (24) savelist ::= */
122, /* (25) relexpr ::= expr */
122, /* (26) relexpr ::= expr PERCENT */
123, /* (27) optrelexpr ::= */
129, /* (28) attribute_list ::= relexpr alist */
132, /* (29) attribute ::= numproperty relexpr */
132, /* (30) attribute ::= dashproperty expr */
132, /* (31) attribute ::= dashproperty */
132, /* (32) attribute ::= colorproperty rvalue */
132, /* (33) attribute ::= go direction optrelexpr */
132, /* (34) attribute ::= go direction even position */
132, /* (35) attribute ::= CLOSE */
132, /* (36) attribute ::= CHOP */
132, /* (37) attribute ::= FROM position */
132, /* (38) attribute ::= TO position */
132, /* (39) attribute ::= THEN */
132, /* (40) attribute ::= THEN optrelexpr HEADING expr */
132, /* (41) attribute ::= THEN optrelexpr EDGEPT */
132, /* (42) attribute ::= GO optrelexpr HEADING expr */
132, /* (43) attribute ::= GO optrelexpr EDGEPT */
132, /* (44) attribute ::= AT position */
132, /* (45) attribute ::= SAME */
132, /* (46) attribute ::= SAME AS object */
132, /* (47) attribute ::= STRING textposition */
132, /* (48) attribute ::= FIT */
132, /* (49) attribute ::= BEHIND object */
135, /* (50) withclause ::= DOT_E edge AT position */
135, /* (51) withclause ::= edge AT position */
106, /* (52) numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
134, /* (53) boolproperty ::= CW */
134, /* (54) boolproperty ::= CCW */
134, /* (55) boolproperty ::= LARROW */
134, /* (56) boolproperty ::= RARROW */
134, /* (57) boolproperty ::= LRARROW */
134, /* (58) boolproperty ::= INVIS */
134, /* (59) boolproperty ::= THICK */
134, /* (60) boolproperty ::= THIN */
134, /* (61) boolproperty ::= SOLID */
118, /* (62) textposition ::= */
118, /* (63) textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */
113, /* (64) position ::= expr COMMA expr */
113, /* (65) position ::= place PLUS expr COMMA expr */
113, /* (66) position ::= place MINUS expr COMMA expr */
113, /* (67) position ::= place PLUS LP expr COMMA expr RP */
113, /* (68) position ::= place MINUS LP expr COMMA expr RP */
113, /* (69) position ::= LP position COMMA position RP */
113, /* (70) position ::= LP position RP */
113, /* (71) position ::= expr between position AND position */
113, /* (72) position ::= expr LT position COMMA position GT */
113, /* (73) position ::= expr ABOVE position */
113, /* (74) position ::= expr BELOW position */
113, /* (75) position ::= expr LEFT OF position */
113, /* (76) position ::= expr RIGHT OF position */
113, /* (77) position ::= expr ON HEADING EDGEPT OF position */
113, /* (78) position ::= expr HEADING EDGEPT OF position */
113, /* (79) position ::= expr EDGEPT OF position */
113, /* (80) position ::= expr ON HEADING expr FROM position */
113, /* (81) position ::= expr HEADING expr FROM position */
114, /* (82) place ::= edge OF object */
137, /* (83) place2 ::= object */
137, /* (84) place2 ::= object DOT_E edge */
137, /* (85) place2 ::= NTH VERTEX OF object */
115, /* (86) object ::= nth */
115, /* (87) object ::= nth OF|IN object */
116, /* (88) objectname ::= THIS */
116, /* (89) objectname ::= PLACENAME */
116, /* (90) objectname ::= objectname DOT_U PLACENAME */
117, /* (91) nth ::= NTH CLASSNAME */
117, /* (92) nth ::= NTH LAST CLASSNAME */
117, /* (93) nth ::= LAST CLASSNAME */
117, /* (94) nth ::= LAST */
117, /* (95) nth ::= NTH LB RB */
117, /* (96) nth ::= NTH LAST LB RB */
117, /* (97) nth ::= LAST LB RB */
105, /* (98) expr ::= expr PLUS expr */
105, /* (99) expr ::= expr MINUS expr */
105, /* (100) expr ::= expr STAR expr */
105, /* (101) expr ::= expr SLASH expr */
105, /* (102) expr ::= MINUS expr */
105, /* (103) expr ::= PLUS expr */
105, /* (104) expr ::= LP expr RP */
105, /* (105) expr ::= LP FILL|COLOR|THICKNESS RP */
105, /* (106) expr ::= NUMBER */
105, /* (107) expr ::= ID */
105, /* (108) expr ::= FUNC1 LP expr RP */
105, /* (109) expr ::= FUNC2 LP expr COMMA expr RP */
105, /* (110) expr ::= DIST LP position COMMA position RP */
105, /* (111) expr ::= place2 DOT_XY X */
105, /* (112) expr ::= place2 DOT_XY Y */
105, /* (113) expr ::= object DOT_L numproperty */
105, /* (114) expr ::= object DOT_L dashproperty */
105, /* (115) expr ::= object DOT_L colorproperty */
120, /* (116) lvalue ::= ID */
120, /* (117) lvalue ::= FILL */
120, /* (118) lvalue ::= COLOR */
120, /* (119) lvalue ::= THICKNESS */
119, /* (120) rvalue ::= expr */
125, /* (121) print ::= PRINT */
126, /* (122) prlist ::= pritem */
126, /* (123) prlist ::= prlist prsep pritem */
109, /* (124) direction ::= UP */
109, /* (125) direction ::= DOWN */
109, /* (126) direction ::= LEFT */
109, /* (127) direction ::= RIGHT */
123, /* (128) optrelexpr ::= relexpr */
129, /* (129) attribute_list ::= alist */
131, /* (130) alist ::= */
131, /* (131) alist ::= alist attribute */
132, /* (132) attribute ::= boolproperty */
132, /* (133) attribute ::= WITH withclause */
133, /* (134) go ::= GO */
133, /* (135) go ::= */
121, /* (136) even ::= UNTIL EVEN WITH */
121, /* (137) even ::= EVEN WITH */
110, /* (138) dashproperty ::= DOTTED */
110, /* (139) dashproperty ::= DASHED */
111, /* (140) colorproperty ::= FILL */
111, /* (141) colorproperty ::= COLOR */
113, /* (142) position ::= place */
136, /* (143) between ::= WAY BETWEEN */
136, /* (144) between ::= BETWEEN */
136, /* (145) between ::= OF THE WAY BETWEEN */
114, /* (146) place ::= place2 */
107, /* (147) edge ::= CENTER */
107, /* (148) edge ::= EDGEPT */
107, /* (149) edge ::= TOP */
107, /* (150) edge ::= BOTTOM */
107, /* (151) edge ::= START */
107, /* (152) edge ::= END */
107, /* (153) edge ::= RIGHT */
107, /* (154) edge ::= LEFT */
115, /* (155) object ::= objectname */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
** of symbols on the right-hand side of that rule. */
static const signed char yyRuleInfoNRhs[] = {
-1, /* (0) document ::= statement_list */
-1, /* (1) statement_list ::= statement */
|
| ︙ | ︙ | |||
2417 2418 2419 2420 2421 2422 2423 |
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* document ::= statement_list */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 |
** { ... } // User supplied code
** #line <lineno> <thisfile>
** break;
*/
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* document ::= statement_list */
#line 563 "pikchr.y"
{pik_render(p,yymsp[0].minor.yy23);}
#line 2479 "pikchr.c"
break;
case 1: /* statement_list ::= statement */
#line 566 "pikchr.y"
{ yylhsminor.yy23 = pik_elist_append(p,0,yymsp[0].minor.yy54); }
#line 2484 "pikchr.c"
yymsp[0].minor.yy23 = yylhsminor.yy23;
break;
case 2: /* statement_list ::= statement_list EOL statement */
#line 568 "pikchr.y"
{ yylhsminor.yy23 = pik_elist_append(p,yymsp[-2].minor.yy23,yymsp[0].minor.yy54); }
#line 2490 "pikchr.c"
yymsp[-2].minor.yy23 = yylhsminor.yy23;
break;
case 3: /* statement ::= */
#line 571 "pikchr.y"
{ yymsp[1].minor.yy54 = 0; }
#line 2496 "pikchr.c"
break;
case 4: /* statement ::= direction */
#line 572 "pikchr.y"
{ pik_set_direction(p,yymsp[0].minor.yy0.eCode); yylhsminor.yy54=0; }
#line 2501 "pikchr.c"
yymsp[0].minor.yy54 = yylhsminor.yy54;
break;
case 5: /* statement ::= lvalue ASSIGN rvalue */
#line 573 "pikchr.y"
{pik_set_var(p,&yymsp[-2].minor.yy0,yymsp[0].minor.yy129,&yymsp[-1].minor.yy0); yylhsminor.yy54=0;}
#line 2507 "pikchr.c"
yymsp[-2].minor.yy54 = yylhsminor.yy54;
break;
case 6: /* statement ::= PLACENAME COLON unnamed_statement */
#line 575 "pikchr.y"
{ yylhsminor.yy54 = yymsp[0].minor.yy54; pik_elem_setname(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0); }
#line 2513 "pikchr.c"
yymsp[-2].minor.yy54 = yylhsminor.yy54;
break;
case 7: /* statement ::= PLACENAME COLON position */
#line 577 "pikchr.y"
{ yylhsminor.yy54 = pik_elem_new(p,0,0,0);
if(yylhsminor.yy54){ yylhsminor.yy54->ptAt = yymsp[0].minor.yy187; pik_elem_setname(p,yylhsminor.yy54,&yymsp[-2].minor.yy0); }}
#line 2520 "pikchr.c"
yymsp[-2].minor.yy54 = yylhsminor.yy54;
break;
case 8: /* statement ::= unnamed_statement */
#line 579 "pikchr.y"
{yylhsminor.yy54 = yymsp[0].minor.yy54;}
#line 2526 "pikchr.c"
yymsp[0].minor.yy54 = yylhsminor.yy54;
break;
case 9: /* statement ::= print prlist */
#line 580 "pikchr.y"
{pik_append(p,"<br>\n",5); yymsp[-1].minor.yy54=0;}
#line 2532 "pikchr.c"
break;
case 10: /* statement ::= ASSERT LP expr EQ expr RP */
#line 585 "pikchr.y"
{yymsp[-5].minor.yy54=pik_assert(p,yymsp[-3].minor.yy129,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy129);}
#line 2537 "pikchr.c"
break;
case 11: /* statement ::= ASSERT LP position EQ position RP */
#line 587 "pikchr.y"
{yymsp[-5].minor.yy54=pik_position_assert(p,&yymsp[-3].minor.yy187,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy187);}
#line 2542 "pikchr.c"
break;
case 12: /* statement ::= DEFINE ID CODEBLOCK */
#line 588 "pikchr.y"
{yymsp[-2].minor.yy54=0; pik_add_macro(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
#line 2547 "pikchr.c"
break;
case 13: /* rvalue ::= PLACENAME */
#line 599 "pikchr.y"
{yylhsminor.yy129 = pik_lookup_color(p,&yymsp[0].minor.yy0);}
#line 2552 "pikchr.c"
yymsp[0].minor.yy129 = yylhsminor.yy129;
break;
case 14: /* pritem ::= FILL */
case 15: /* pritem ::= COLOR */ yytestcase(yyruleno==15);
case 16: /* pritem ::= THICKNESS */ yytestcase(yyruleno==16);
#line 604 "pikchr.y"
{pik_append_num(p,"",pik_value(p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.n,0));}
#line 2560 "pikchr.c"
break;
case 17: /* pritem ::= rvalue */
#line 607 "pikchr.y"
{pik_append_num(p,"",yymsp[0].minor.yy129);}
#line 2565 "pikchr.c"
break;
case 18: /* pritem ::= STRING */
#line 608 "pikchr.y"
{pik_append_text(p,yymsp[0].minor.yy0.z+1,yymsp[0].minor.yy0.n-2,0);}
#line 2570 "pikchr.c"
break;
case 19: /* prsep ::= COMMA */
#line 609 "pikchr.y"
{pik_append(p, " ", 1);}
#line 2575 "pikchr.c"
break;
case 20: /* unnamed_statement ::= basetype attribute_list */
#line 614 "pikchr.y"
{yylhsminor.yy54 = yymsp[-1].minor.yy54; pik_after_adding_attributes(p,yylhsminor.yy54);}
#line 2580 "pikchr.c"
yymsp[-1].minor.yy54 = yylhsminor.yy54;
break;
case 21: /* basetype ::= CLASSNAME */
#line 616 "pikchr.y"
{yylhsminor.yy54 = pik_elem_new(p,&yymsp[0].minor.yy0,0,0); }
#line 2586 "pikchr.c"
yymsp[0].minor.yy54 = yylhsminor.yy54;
break;
case 22: /* basetype ::= STRING textposition */
#line 618 "pikchr.y"
{yymsp[-1].minor.yy0.eCode = yymsp[0].minor.yy272; yylhsminor.yy54 = pik_elem_new(p,0,&yymsp[-1].minor.yy0,0); }
#line 2592 "pikchr.c"
yymsp[-1].minor.yy54 = yylhsminor.yy54;
break;
case 23: /* basetype ::= LB savelist statement_list RB */
#line 620 "pikchr.y"
{ p->list = yymsp[-2].minor.yy23; yymsp[-3].minor.yy54 = pik_elem_new(p,0,0,yymsp[-1].minor.yy23); if(yymsp[-3].minor.yy54) yymsp[-3].minor.yy54->errTok = yymsp[0].minor.yy0; }
#line 2598 "pikchr.c"
break;
case 24: /* savelist ::= */
#line 625 "pikchr.y"
{yymsp[1].minor.yy23 = p->list; p->list = 0;}
#line 2603 "pikchr.c"
break;
case 25: /* relexpr ::= expr */
#line 632 "pikchr.y"
{yylhsminor.yy28.rAbs = yymsp[0].minor.yy129; yylhsminor.yy28.rRel = 0;}
#line 2608 "pikchr.c"
yymsp[0].minor.yy28 = yylhsminor.yy28;
break;
case 26: /* relexpr ::= expr PERCENT */
#line 633 "pikchr.y"
{yylhsminor.yy28.rAbs = 0; yylhsminor.yy28.rRel = yymsp[-1].minor.yy129/100;}
#line 2614 "pikchr.c"
yymsp[-1].minor.yy28 = yylhsminor.yy28;
break;
case 27: /* optrelexpr ::= */
#line 635 "pikchr.y"
{yymsp[1].minor.yy28.rAbs = 0; yymsp[1].minor.yy28.rRel = 1.0;}
#line 2620 "pikchr.c"
break;
case 28: /* attribute_list ::= relexpr alist */
#line 637 "pikchr.y"
{pik_add_direction(p,0,&yymsp[-1].minor.yy28);}
#line 2625 "pikchr.c"
break;
case 29: /* attribute ::= numproperty relexpr */
#line 641 "pikchr.y"
{ pik_set_numprop(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy28); }
#line 2630 "pikchr.c"
break;
case 30: /* attribute ::= dashproperty expr */
#line 642 "pikchr.y"
{ pik_set_dashed(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy129); }
#line 2635 "pikchr.c"
break;
case 31: /* attribute ::= dashproperty */
#line 643 "pikchr.y"
{ pik_set_dashed(p,&yymsp[0].minor.yy0,0); }
#line 2640 "pikchr.c"
break;
case 32: /* attribute ::= colorproperty rvalue */
#line 644 "pikchr.y"
{ pik_set_clrprop(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy129); }
#line 2645 "pikchr.c"
break;
case 33: /* attribute ::= go direction optrelexpr */
#line 645 "pikchr.y"
{ pik_add_direction(p,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy28);}
#line 2650 "pikchr.c"
break;
case 34: /* attribute ::= go direction even position */
#line 646 "pikchr.y"
{pik_evenwith(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy187);}
#line 2655 "pikchr.c"
break;
case 35: /* attribute ::= CLOSE */
#line 647 "pikchr.y"
{ pik_close_path(p,&yymsp[0].minor.yy0); }
#line 2660 "pikchr.c"
break;
case 36: /* attribute ::= CHOP */
#line 648 "pikchr.y"
{ p->cur->bChop = 1; }
#line 2665 "pikchr.c"
break;
case 37: /* attribute ::= FROM position */
#line 649 "pikchr.y"
{ pik_set_from(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy187); }
#line 2670 "pikchr.c"
break;
case 38: /* attribute ::= TO position */
#line 650 "pikchr.y"
{ pik_add_to(p,p->cur,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy187); }
#line 2675 "pikchr.c"
break;
case 39: /* attribute ::= THEN */
#line 651 "pikchr.y"
{ pik_then(p, &yymsp[0].minor.yy0, p->cur); }
#line 2680 "pikchr.c"
break;
case 40: /* attribute ::= THEN optrelexpr HEADING expr */
case 42: /* attribute ::= GO optrelexpr HEADING expr */ yytestcase(yyruleno==42);
#line 653 "pikchr.y"
{pik_move_hdg(p,&yymsp[-2].minor.yy28,&yymsp[-1].minor.yy0,yymsp[0].minor.yy129,0,&yymsp[-3].minor.yy0);}
#line 2686 "pikchr.c"
break;
case 41: /* attribute ::= THEN optrelexpr EDGEPT */
case 43: /* attribute ::= GO optrelexpr EDGEPT */ yytestcase(yyruleno==43);
#line 654 "pikchr.y"
{pik_move_hdg(p,&yymsp[-1].minor.yy28,0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0);}
#line 2692 "pikchr.c"
break;
case 44: /* attribute ::= AT position */
#line 659 "pikchr.y"
{ pik_set_at(p,0,&yymsp[0].minor.yy187,&yymsp[-1].minor.yy0); }
#line 2697 "pikchr.c"
break;
case 45: /* attribute ::= SAME */
#line 661 "pikchr.y"
{pik_same(p,0,&yymsp[0].minor.yy0);}
#line 2702 "pikchr.c"
break;
case 46: /* attribute ::= SAME AS object */
#line 662 "pikchr.y"
{pik_same(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);}
#line 2707 "pikchr.c"
break;
case 47: /* attribute ::= STRING textposition */
#line 663 "pikchr.y"
{pik_add_txt(p,&yymsp[-1].minor.yy0,yymsp[0].minor.yy272);}
#line 2712 "pikchr.c"
break;
case 48: /* attribute ::= FIT */
#line 664 "pikchr.y"
{pik_size_to_fit(p,0,&yymsp[0].minor.yy0,3); }
#line 2717 "pikchr.c"
break;
case 49: /* attribute ::= BEHIND object */
#line 665 "pikchr.y"
{pik_behind(p,yymsp[0].minor.yy54);}
#line 2722 "pikchr.c"
break;
case 50: /* withclause ::= DOT_E edge AT position */
case 51: /* withclause ::= edge AT position */ yytestcase(yyruleno==51);
#line 673 "pikchr.y"
{ pik_set_at(p,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy187,&yymsp[-1].minor.yy0); }
#line 2728 "pikchr.c"
break;
case 52: /* numproperty ::= HEIGHT|WIDTH|RADIUS|DIAMETER|THICKNESS */
#line 677 "pikchr.y"
{yylhsminor.yy0 = yymsp[0].minor.yy0;}
#line 2733 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 53: /* boolproperty ::= CW */
#line 688 "pikchr.y"
{p->cur->cw = 1;}
#line 2739 "pikchr.c"
break;
case 54: /* boolproperty ::= CCW */
#line 689 "pikchr.y"
{p->cur->cw = 0;}
#line 2744 "pikchr.c"
break;
case 55: /* boolproperty ::= LARROW */
#line 690 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=0; }
#line 2749 "pikchr.c"
break;
case 56: /* boolproperty ::= RARROW */
#line 691 "pikchr.y"
{p->cur->larrow=0; p->cur->rarrow=1; }
#line 2754 "pikchr.c"
break;
case 57: /* boolproperty ::= LRARROW */
#line 692 "pikchr.y"
{p->cur->larrow=1; p->cur->rarrow=1; }
#line 2759 "pikchr.c"
break;
case 58: /* boolproperty ::= INVIS */
#line 693 "pikchr.y"
{p->cur->sw = -0.00001;}
#line 2764 "pikchr.c"
break;
case 59: /* boolproperty ::= THICK */
#line 694 "pikchr.y"
{p->cur->sw *= 1.5;}
#line 2769 "pikchr.c"
break;
case 60: /* boolproperty ::= THIN */
#line 695 "pikchr.y"
{p->cur->sw *= 0.67;}
#line 2774 "pikchr.c"
break;
case 61: /* boolproperty ::= SOLID */
#line 696 "pikchr.y"
{p->cur->sw = pik_value(p,"thickness",9,0);
p->cur->dotted = p->cur->dashed = 0.0;}
#line 2780 "pikchr.c"
break;
case 62: /* textposition ::= */
#line 699 "pikchr.y"
{yymsp[1].minor.yy272 = 0;}
#line 2785 "pikchr.c"
break;
case 63: /* textposition ::= textposition CENTER|LJUST|RJUST|ABOVE|BELOW|ITALIC|BOLD|MONO|ALIGNED|BIG|SMALL */
#line 702 "pikchr.y"
{yylhsminor.yy272 = (short int)pik_text_position(yymsp[-1].minor.yy272,&yymsp[0].minor.yy0);}
#line 2790 "pikchr.c"
yymsp[-1].minor.yy272 = yylhsminor.yy272;
break;
case 64: /* position ::= expr COMMA expr */
#line 705 "pikchr.y"
{yylhsminor.yy187.x=yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[0].minor.yy129;}
#line 2796 "pikchr.c"
yymsp[-2].minor.yy187 = yylhsminor.yy187;
break;
case 65: /* position ::= place PLUS expr COMMA expr */
#line 707 "pikchr.y"
{yylhsminor.yy187.x=yymsp[-4].minor.yy187.x+yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[-4].minor.yy187.y+yymsp[0].minor.yy129;}
#line 2802 "pikchr.c"
yymsp[-4].minor.yy187 = yylhsminor.yy187;
break;
case 66: /* position ::= place MINUS expr COMMA expr */
#line 708 "pikchr.y"
{yylhsminor.yy187.x=yymsp[-4].minor.yy187.x-yymsp[-2].minor.yy129; yylhsminor.yy187.y=yymsp[-4].minor.yy187.y-yymsp[0].minor.yy129;}
#line 2808 "pikchr.c"
yymsp[-4].minor.yy187 = yylhsminor.yy187;
break;
case 67: /* position ::= place PLUS LP expr COMMA expr RP */
#line 710 "pikchr.y"
{yylhsminor.yy187.x=yymsp[-6].minor.yy187.x+yymsp[-3].minor.yy129; yylhsminor.yy187.y=yymsp[-6].minor.yy187.y+yymsp[-1].minor.yy129;}
#line 2814 "pikchr.c"
yymsp[-6].minor.yy187 = yylhsminor.yy187;
break;
case 68: /* position ::= place MINUS LP expr COMMA expr RP */
#line 712 "pikchr.y"
{yylhsminor.yy187.x=yymsp[-6].minor.yy187.x-yymsp[-3].minor.yy129; yylhsminor.yy187.y=yymsp[-6].minor.yy187.y-yymsp[-1].minor.yy129;}
#line 2820 "pikchr.c"
yymsp[-6].minor.yy187 = yylhsminor.yy187;
break;
case 69: /* position ::= LP position COMMA position RP */
#line 713 "pikchr.y"
{yymsp[-4].minor.yy187.x=yymsp[-3].minor.yy187.x; yymsp[-4].minor.yy187.y=yymsp[-1].minor.yy187.y;}
#line 2826 "pikchr.c"
break;
case 70: /* position ::= LP position RP */
#line 714 "pikchr.y"
{yymsp[-2].minor.yy187=yymsp[-1].minor.yy187;}
#line 2831 "pikchr.c"
break;
case 71: /* position ::= expr between position AND position */
#line 716 "pikchr.y"
{yylhsminor.yy187 = pik_position_between(yymsp[-4].minor.yy129,yymsp[-2].minor.yy187,yymsp[0].minor.yy187);}
#line 2836 "pikchr.c"
yymsp[-4].minor.yy187 = yylhsminor.yy187;
break;
case 72: /* position ::= expr LT position COMMA position GT */
#line 718 "pikchr.y"
{yylhsminor.yy187 = pik_position_between(yymsp[-5].minor.yy129,yymsp[-3].minor.yy187,yymsp[-1].minor.yy187);}
#line 2842 "pikchr.c"
yymsp[-5].minor.yy187 = yylhsminor.yy187;
break;
case 73: /* position ::= expr ABOVE position */
#line 719 "pikchr.y"
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.y += yymsp[-2].minor.yy129;}
#line 2848 "pikchr.c"
yymsp[-2].minor.yy187 = yylhsminor.yy187;
break;
case 74: /* position ::= expr BELOW position */
#line 720 "pikchr.y"
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.y -= yymsp[-2].minor.yy129;}
#line 2854 "pikchr.c"
yymsp[-2].minor.yy187 = yylhsminor.yy187;
break;
case 75: /* position ::= expr LEFT OF position */
#line 721 "pikchr.y"
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.x -= yymsp[-3].minor.yy129;}
#line 2860 "pikchr.c"
yymsp[-3].minor.yy187 = yylhsminor.yy187;
break;
case 76: /* position ::= expr RIGHT OF position */
#line 722 "pikchr.y"
{yylhsminor.yy187=yymsp[0].minor.yy187; yylhsminor.yy187.x += yymsp[-3].minor.yy129;}
#line 2866 "pikchr.c"
yymsp[-3].minor.yy187 = yylhsminor.yy187;
break;
case 77: /* position ::= expr ON HEADING EDGEPT OF position */
#line 724 "pikchr.y"
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-5].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);}
#line 2872 "pikchr.c"
yymsp[-5].minor.yy187 = yylhsminor.yy187;
break;
case 78: /* position ::= expr HEADING EDGEPT OF position */
#line 726 "pikchr.y"
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-4].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);}
#line 2878 "pikchr.c"
yymsp[-4].minor.yy187 = yylhsminor.yy187;
break;
case 79: /* position ::= expr EDGEPT OF position */
#line 728 "pikchr.y"
{yylhsminor.yy187 = pik_position_at_hdg(yymsp[-3].minor.yy129,&yymsp[-2].minor.yy0,yymsp[0].minor.yy187);}
#line 2884 "pikchr.c"
yymsp[-3].minor.yy187 = yylhsminor.yy187;
break;
case 80: /* position ::= expr ON HEADING expr FROM position */
#line 730 "pikchr.y"
{yylhsminor.yy187 = pik_position_at_angle(yymsp[-5].minor.yy129,yymsp[-2].minor.yy129,yymsp[0].minor.yy187);}
#line 2890 "pikchr.c"
yymsp[-5].minor.yy187 = yylhsminor.yy187;
break;
case 81: /* position ::= expr HEADING expr FROM position */
#line 732 "pikchr.y"
{yylhsminor.yy187 = pik_position_at_angle(yymsp[-4].minor.yy129,yymsp[-2].minor.yy129,yymsp[0].minor.yy187);}
#line 2896 "pikchr.c"
yymsp[-4].minor.yy187 = yylhsminor.yy187;
break;
case 82: /* place ::= edge OF object */
#line 744 "pikchr.y"
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);}
#line 2902 "pikchr.c"
yymsp[-2].minor.yy187 = yylhsminor.yy187;
break;
case 83: /* place2 ::= object */
#line 745 "pikchr.y"
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[0].minor.yy54,0);}
#line 2908 "pikchr.c"
yymsp[0].minor.yy187 = yylhsminor.yy187;
break;
case 84: /* place2 ::= object DOT_E edge */
#line 746 "pikchr.y"
{yylhsminor.yy187 = pik_place_of_elem(p,yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);}
#line 2914 "pikchr.c"
yymsp[-2].minor.yy187 = yylhsminor.yy187;
break;
case 85: /* place2 ::= NTH VERTEX OF object */
#line 747 "pikchr.y"
{yylhsminor.yy187 = pik_nth_vertex(p,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,yymsp[0].minor.yy54);}
#line 2920 "pikchr.c"
yymsp[-3].minor.yy187 = yylhsminor.yy187;
break;
case 86: /* object ::= nth */
#line 759 "pikchr.y"
{yylhsminor.yy54 = pik_find_nth(p,0,&yymsp[0].minor.yy0);}
#line 2926 "pikchr.c"
yymsp[0].minor.yy54 = yylhsminor.yy54;
break;
case 87: /* object ::= nth OF|IN object */
#line 760 "pikchr.y"
{yylhsminor.yy54 = pik_find_nth(p,yymsp[0].minor.yy54,&yymsp[-2].minor.yy0);}
#line 2932 "pikchr.c"
yymsp[-2].minor.yy54 = yylhsminor.yy54;
break;
case 88: /* objectname ::= THIS */
#line 762 "pikchr.y"
{yymsp[0].minor.yy54 = p->cur;}
#line 2938 "pikchr.c"
break;
case 89: /* objectname ::= PLACENAME */
#line 763 "pikchr.y"
{yylhsminor.yy54 = pik_find_byname(p,0,&yymsp[0].minor.yy0);}
#line 2943 "pikchr.c"
yymsp[0].minor.yy54 = yylhsminor.yy54;
break;
case 90: /* objectname ::= objectname DOT_U PLACENAME */
#line 765 "pikchr.y"
{yylhsminor.yy54 = pik_find_byname(p,yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);}
#line 2949 "pikchr.c"
yymsp[-2].minor.yy54 = yylhsminor.yy54;
break;
case 91: /* nth ::= NTH CLASSNAME */
#line 767 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-1].minor.yy0); }
#line 2955 "pikchr.c"
yymsp[-1].minor.yy0 = yylhsminor.yy0;
break;
case 92: /* nth ::= NTH LAST CLASSNAME */
#line 768 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-2].minor.yy0); }
#line 2961 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 93: /* nth ::= LAST CLASSNAME */
#line 769 "pikchr.y"
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.eCode = -1;}
#line 2967 "pikchr.c"
break;
case 94: /* nth ::= LAST */
#line 770 "pikchr.y"
{yylhsminor.yy0=yymsp[0].minor.yy0; yylhsminor.yy0.eCode = -1;}
#line 2972 "pikchr.c"
yymsp[0].minor.yy0 = yylhsminor.yy0;
break;
case 95: /* nth ::= NTH LB RB */
#line 771 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = pik_nth_value(p,&yymsp[-2].minor.yy0);}
#line 2978 "pikchr.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0;
break;
case 96: /* nth ::= NTH LAST LB RB */
#line 772 "pikchr.y"
{yylhsminor.yy0=yymsp[-1].minor.yy0; yylhsminor.yy0.eCode = -pik_nth_value(p,&yymsp[-3].minor.yy0);}
#line 2984 "pikchr.c"
yymsp[-3].minor.yy0 = yylhsminor.yy0;
break;
case 97: /* nth ::= LAST LB RB */
#line 773 "pikchr.y"
{yymsp[-2].minor.yy0=yymsp[-1].minor.yy0; yymsp[-2].minor.yy0.eCode = -1; }
#line 2990 "pikchr.c"
break;
case 98: /* expr ::= expr PLUS expr */
#line 775 "pikchr.y"
{yylhsminor.yy129=yymsp[-2].minor.yy129+yymsp[0].minor.yy129;}
#line 2995 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 99: /* expr ::= expr MINUS expr */
#line 776 "pikchr.y"
{yylhsminor.yy129=yymsp[-2].minor.yy129-yymsp[0].minor.yy129;}
#line 3001 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 100: /* expr ::= expr STAR expr */
#line 777 "pikchr.y"
{yylhsminor.yy129=yymsp[-2].minor.yy129*yymsp[0].minor.yy129;}
#line 3007 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 101: /* expr ::= expr SLASH expr */
#line 778 "pikchr.y"
{
if( yymsp[0].minor.yy129==0.0 ){ pik_error(p, &yymsp[-1].minor.yy0, "division by zero"); yylhsminor.yy129 = 0.0; }
else{ yylhsminor.yy129 = yymsp[-2].minor.yy129/yymsp[0].minor.yy129; }
}
#line 3016 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 102: /* expr ::= MINUS expr */
#line 782 "pikchr.y"
{yymsp[-1].minor.yy129=-yymsp[0].minor.yy129;}
#line 3022 "pikchr.c"
break;
case 103: /* expr ::= PLUS expr */
#line 783 "pikchr.y"
{yymsp[-1].minor.yy129=yymsp[0].minor.yy129;}
#line 3027 "pikchr.c"
break;
case 104: /* expr ::= LP expr RP */
#line 784 "pikchr.y"
{yymsp[-2].minor.yy129=yymsp[-1].minor.yy129;}
#line 3032 "pikchr.c"
break;
case 105: /* expr ::= LP FILL|COLOR|THICKNESS RP */
#line 785 "pikchr.y"
{yymsp[-2].minor.yy129=pik_get_var(p,&yymsp[-1].minor.yy0);}
#line 3037 "pikchr.c"
break;
case 106: /* expr ::= NUMBER */
#line 786 "pikchr.y"
{yylhsminor.yy129=pik_atof(&yymsp[0].minor.yy0);}
#line 3042 "pikchr.c"
yymsp[0].minor.yy129 = yylhsminor.yy129;
break;
case 107: /* expr ::= ID */
#line 787 "pikchr.y"
{yylhsminor.yy129=pik_get_var(p,&yymsp[0].minor.yy0);}
#line 3048 "pikchr.c"
yymsp[0].minor.yy129 = yylhsminor.yy129;
break;
case 108: /* expr ::= FUNC1 LP expr RP */
#line 788 "pikchr.y"
{yylhsminor.yy129 = pik_func(p,&yymsp[-3].minor.yy0,yymsp[-1].minor.yy129,0.0);}
#line 3054 "pikchr.c"
yymsp[-3].minor.yy129 = yylhsminor.yy129;
break;
case 109: /* expr ::= FUNC2 LP expr COMMA expr RP */
#line 789 "pikchr.y"
{yylhsminor.yy129 = pik_func(p,&yymsp[-5].minor.yy0,yymsp[-3].minor.yy129,yymsp[-1].minor.yy129);}
#line 3060 "pikchr.c"
yymsp[-5].minor.yy129 = yylhsminor.yy129;
break;
case 110: /* expr ::= DIST LP position COMMA position RP */
#line 790 "pikchr.y"
{yymsp[-5].minor.yy129 = pik_dist(&yymsp[-3].minor.yy187,&yymsp[-1].minor.yy187);}
#line 3066 "pikchr.c"
break;
case 111: /* expr ::= place2 DOT_XY X */
#line 791 "pikchr.y"
{yylhsminor.yy129 = yymsp[-2].minor.yy187.x;}
#line 3071 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 112: /* expr ::= place2 DOT_XY Y */
#line 792 "pikchr.y"
{yylhsminor.yy129 = yymsp[-2].minor.yy187.y;}
#line 3077 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
case 113: /* expr ::= object DOT_L numproperty */
case 114: /* expr ::= object DOT_L dashproperty */ yytestcase(yyruleno==114);
case 115: /* expr ::= object DOT_L colorproperty */ yytestcase(yyruleno==115);
#line 793 "pikchr.y"
{yylhsminor.yy129=pik_property_of(yymsp[-2].minor.yy54,&yymsp[0].minor.yy0);}
#line 3085 "pikchr.c"
yymsp[-2].minor.yy129 = yylhsminor.yy129;
break;
default:
/* (116) lvalue ::= ID */ yytestcase(yyruleno==116);
/* (117) lvalue ::= FILL */ yytestcase(yyruleno==117);
/* (118) lvalue ::= COLOR */ yytestcase(yyruleno==118);
/* (119) lvalue ::= THICKNESS */ yytestcase(yyruleno==119);
/* (120) rvalue ::= expr */ yytestcase(yyruleno==120);
|
| ︙ | ︙ | |||
3128 3129 3130 3131 3132 3133 3134 |
int yymajor, /* The major type of the error token */
pik_parserTOKENTYPE yyminor /* The minor type of the error token */
){
pik_parserARG_FETCH
pik_parserCTX_FETCH
#define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/
| | | | 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 |
int yymajor, /* The major type of the error token */
pik_parserTOKENTYPE yyminor /* The minor type of the error token */
){
pik_parserARG_FETCH
pik_parserCTX_FETCH
#define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/
#line 551 "pikchr.y"
if( TOKEN.z && TOKEN.z[0] ){
pik_error(p, &TOKEN, "syntax error");
}else{
pik_error(p, 0, "syntax error");
}
UNUSED_PARAMETER(yymajor);
#line 3196 "pikchr.c"
/************ End %syntax_error code ******************************************/
pik_parserARG_STORE /* Suppress warning about unused %extra_argument variable */
pik_parserCTX_STORE
}
/*
** The following is executed when the parser accepts
|
| ︙ | ︙ | |||
3405 3406 3407 3408 3409 3410 3411 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } | | | 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 | assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ); return yyFallback[iToken]; #else (void)iToken; return 0; #endif } #line 798 "pikchr.y" /* Chart of the 148 official CSS color names with their ** corresponding RGB values thru Color Module Level 4: ** https://developer.mozilla.org/en-US/docs/Web/CSS/color_value ** |
| ︙ | ︙ | |||
3632 3633 3634 3635 3636 3637 3638 | } /* Hack: Arcs are here rendered as quadratic Bezier curves rather ** than true arcs. Multiple reasons: (1) the legacy-PIC parameters ** that control arcs are obscure and I could not figure out what they ** mean based on available documentation. (2) Arcs are rarely used, ** and so do not seem that important. */ | | | | | | | > > > > | > > > > > > > > > > | > | | 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 |
}
/* Hack: Arcs are here rendered as quadratic Bezier curves rather
** than true arcs. Multiple reasons: (1) the legacy-PIC parameters
** that control arcs are obscure and I could not figure out what they
** mean based on available documentation. (2) Arcs are rarely used,
** and so do not seem that important.
*/
static PPoint arcControlPoint(int cw, PPoint f, PPoint t){
PPoint m;
PNum dx, dy;
m.x = 0.5*(f.x+t.x);
m.y = 0.5*(f.y+t.y);
dx = t.x - f.x;
dy = t.y - f.y;
if( cw ){
m.x -= 0.5*dy;
m.y += 0.5*dx;
}else{
m.x += 0.5*dy;
m.y -= 0.5*dx;
}
return m;
}
static void arcCheck(Pik *p, PObj *pObj){
PPoint f, m, t;
PNum sw;
int i;
if( p->nTPath>2 ){
pik_error(p, &pObj->errTok, "arc geometry error");
return;
}
f = p->aTPath[0];
t = p->aTPath[1];
m = arcControlPoint(pObj->cw, f, t);
sw = pObj->sw;
for(i=1; i<16; i++){
PNum t1, t2, a, b, c, x, y;
t1 = 0.0625*i;
t2 = 1.0 - t1;
a = t2*t2;
b = 2*t1*t2;
c = t1*t1;
x = a*f.x + b*m.x + c*t.x;
y = a*f.y + b*m.y + c*t.y;
pik_bbox_addellipse(&pObj->bbox, x, y, sw, sw);
}
}
static void arcRender(Pik *p, PObj *pObj){
PPoint f, m, t;
if( pObj->nPath<2 ) return;
if( pObj->sw<0.0 ) return;
f = pObj->aPath[0];
t = pObj->aPath[1];
m = arcControlPoint(pObj->cw,f,t);
if( pObj->larrow ){
pik_draw_arrowhead(p,&m,&f,pObj);
}
if( pObj->rarrow ){
pik_draw_arrowhead(p,&m,&t,pObj);
}
pik_append_xy(p,"<path d=\"M", f.x, f.y);
|
| ︙ | ︙ | |||
4336 4337 4338 4339 4340 4341 4342 |
pObj->sw = 0.0;
}
static PPoint textOffset(Pik *p, PObj *pObj, int cp){
/* Automatically slim-down the width and height of text
** statements so that the bounding box tightly encloses the text,
** then get boxOffset() to do the offset computation.
*/
| | | 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 |
pObj->sw = 0.0;
}
static PPoint textOffset(Pik *p, PObj *pObj, int cp){
/* Automatically slim-down the width and height of text
** statements so that the bounding box tightly encloses the text,
** then get boxOffset() to do the offset computation.
*/
pik_size_to_fit(p, pObj, &pObj->errTok,3);
return boxOffset(p, pObj, cp);
}
static void textRender(Pik *p, PObj *pObj){
pik_append_txt(p, pObj, 0);
}
|
| ︙ | ︙ | |||
6345 6346 6347 6348 6349 6350 6351 | ** ** The eWhich parameter is: ** ** 1: Fit horizontally only ** 2: Fit vertically only ** 3: Fit both ways */ | | < | | 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 |
**
** The eWhich parameter is:
**
** 1: Fit horizontally only
** 2: Fit vertically only
** 3: Fit both ways
*/
static void pik_size_to_fit(Pik *p, PObj *pObj, PToken *pFit, int eWhich){
PNum w, h;
PBox bbox;
if( p->nErr ) return;
if( pObj==0 ) pObj = p->cur;
if( pObj->nTxt==0 ){
pik_error(0, pFit, "no text to fit to");
return;
}
if( pObj->type->xFit==0 ) return;
pik_bbox_init(&bbox);
|
| ︙ | ︙ | |||
6493 6494 6495 6496 6497 6498 6499 |
const char *zClr;
int c1, c2;
unsigned int i;
mid = (first+last)/2;
zClr = aColor[mid].zName;
for(i=0; i<pId->n; i++){
c1 = zClr[i]&0x7f;
| | | | 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 |
const char *zClr;
int c1, c2;
unsigned int i;
mid = (first+last)/2;
zClr = aColor[mid].zName;
for(i=0; i<pId->n; i++){
c1 = zClr[i]&0x7f;
if( IsUpper(c1) ) c1 = ToLower(c1);
c2 = pId->z[i]&0x7f;
if( IsUpper(c2) ) c2 = ToLower(c2);
c = c2 - c1;
if( c ) break;
}
if( c==0 && aColor[mid].zName[pId->n] ) c = -1;
if( c==0 ) return (double)aColor[mid].val;
if( c>0 ){
first = mid+1;
|
| ︙ | ︙ | |||
6894 6895 6896 6897 6898 6899 6900 |
/* A height or width less than or equal to zero means "autofit".
** Change the height or width to be big enough to contain the text,
*/
if( pObj->h<=0.0 ){
if( pObj->nTxt==0 ){
pObj->h = 0.0;
}else if( pObj->w<=0.0 ){
| | | | | 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 |
/* A height or width less than or equal to zero means "autofit".
** Change the height or width to be big enough to contain the text,
*/
if( pObj->h<=0.0 ){
if( pObj->nTxt==0 ){
pObj->h = 0.0;
}else if( pObj->w<=0.0 ){
pik_size_to_fit(p, pObj, &pObj->errTok, 3);
}else{
pik_size_to_fit(p, pObj, &pObj->errTok, 2);
}
}
if( pObj->w<=0.0 ){
if( pObj->nTxt==0 ){
pObj->w = 0.0;
}else{
pik_size_to_fit(p, pObj, &pObj->errTok, 1);
}
}
ofst = pik_elem_offset(p, pObj, pObj->eWith);
dx = (pObj->with.x - ofst.x) - pObj->ptAt.x;
dy = (pObj->with.y - ofst.y) - pObj->ptAt.y;
if( dx!=0 || dy!=0 ){
pik_elem_move(pObj, dx, dy);
|
| ︙ | ︙ | |||
7233 7234 7235 7236 7237 7238 7239 |
p->wSVG = pik_round(p->wSVG*pikScale);
p->hSVG = pik_round(p->hSVG*pikScale);
pik_append_num(p, " width=\"", p->wSVG);
pik_append_num(p, "\" height=\"", p->hSVG);
pik_append(p, "\"", 1);
}
pik_append_dis(p, " viewBox=\"0 0 ",w,"");
| | > | 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 |
p->wSVG = pik_round(p->wSVG*pikScale);
p->hSVG = pik_round(p->hSVG*pikScale);
pik_append_num(p, " width=\"", p->wSVG);
pik_append_num(p, "\" height=\"", p->hSVG);
pik_append(p, "\"", 1);
}
pik_append_dis(p, " viewBox=\"0 0 ",w,"");
pik_append_dis(p, " ",h,"\"");
pik_append(p, " data-pikchr-date=\"" MANIFEST_ISODATE "\">\n", -1);
pik_elist_render(p, pList);
pik_append(p,"</svg>\n", -1);
}else{
p->wSVG = -1;
p->hSVG = -1;
}
pik_elist_free(p, pList);
|
| ︙ | ︙ | |||
7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 |
{ "mono", 4, T_MONO, 0, 0 },
{ "monospace", 9, T_MONO, 0, 0 },
{ "n", 1, T_EDGEPT, 0, CP_N },
{ "ne", 2, T_EDGEPT, 0, CP_NE },
{ "north", 5, T_EDGEPT, 0, CP_N },
{ "nw", 2, T_EDGEPT, 0, CP_NW },
{ "of", 2, T_OF, 0, 0 },
{ "previous", 8, T_LAST, 0, 0, },
{ "print", 5, T_PRINT, 0, 0 },
{ "rad", 3, T_RADIUS, 0, 0 },
{ "radius", 6, T_RADIUS, 0, 0 },
{ "right", 5, T_RIGHT, DIR_RIGHT, CP_E },
{ "rjust", 5, T_RJUST, 0, 0 },
{ "s", 1, T_EDGEPT, 0, CP_S },
| > | 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 |
{ "mono", 4, T_MONO, 0, 0 },
{ "monospace", 9, T_MONO, 0, 0 },
{ "n", 1, T_EDGEPT, 0, CP_N },
{ "ne", 2, T_EDGEPT, 0, CP_NE },
{ "north", 5, T_EDGEPT, 0, CP_N },
{ "nw", 2, T_EDGEPT, 0, CP_NW },
{ "of", 2, T_OF, 0, 0 },
{ "pikchr_date",11, T_ISODATE, 0, 0, },
{ "previous", 8, T_LAST, 0, 0, },
{ "print", 5, T_PRINT, 0, 0 },
{ "rad", 3, T_RADIUS, 0, 0 },
{ "radius", 6, T_RADIUS, 0, 0 },
{ "right", 5, T_RIGHT, DIR_RIGHT, CP_E },
{ "rjust", 5, T_RJUST, 0, 0 },
{ "s", 1, T_EDGEPT, 0, CP_S },
|
| ︙ | ︙ | |||
7603 7604 7605 7606 7607 7608 7609 |
pToken->eType = T_ERROR;
return 1;
}
default: {
c = z[0];
if( c=='.' ){
unsigned char c1 = z[1];
| | | | | | | 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 |
pToken->eType = T_ERROR;
return 1;
}
default: {
c = z[0];
if( c=='.' ){
unsigned char c1 = z[1];
if( IsLower(c1) ){
const PikWord *pFound;
for(i=2; (c = z[i])>='a' && c<='z'; i++){}
pFound = pik_find_word((const char*)z+1, i-1,
pik_keywords, count(pik_keywords));
if( pFound && (pFound->eEdge>0 ||
pFound->eType==T_EDGEPT ||
pFound->eType==T_START ||
pFound->eType==T_END )
){
/* Dot followed by something that is a 2-D place value */
pToken->eType = T_DOT_E;
}else if( pFound && (pFound->eType==T_X || pFound->eType==T_Y) ){
/* Dot followed by "x" or "y" */
pToken->eType = T_DOT_XY;
}else{
/* Any other "dot" */
pToken->eType = T_DOT_L;
}
return 1;
}else if( IsDigit(c1) ){
i = 0;
/* no-op. Fall through to number handling */
}else if( IsUpper(c1) ){
for(i=2; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){}
pToken->eType = T_DOT_U;
return 1;
}else{
pToken->eType = T_ERROR;
return 1;
}
}
if( (c>='0' && c<='9') || c=='.' ){
int nDigit;
int isInt = 1;
if( c!='.' ){
nDigit = 1;
for(i=1; (c = z[i])>='0' && c<='9'; i++){ nDigit++; }
if( i==1 && (c=='x' || c=='X') ){
for(i=2; (c = z[i])!=0 && IsXDigit(c); i++){}
pToken->eType = T_NUMBER;
return i;
}
}else{
isInt = 0;
nDigit = 0;
i = 0;
|
| ︙ | ︙ | |||
7698 7699 7700 7701 7702 7703 7704 |
|| (c=='p' && c2=='x')
|| (c=='p' && c2=='c')
){
i += 2;
}
pToken->eType = T_NUMBER;
return i;
| | | | | | | 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 |
|| (c=='p' && c2=='x')
|| (c=='p' && c2=='c')
){
i += 2;
}
pToken->eType = T_NUMBER;
return i;
}else if( IsLower(c) ){
const PikWord *pFound;
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){}
pFound = pik_find_word((const char*)z, i,
pik_keywords, count(pik_keywords));
if( pFound ){
pToken->eType = pFound->eType;
pToken->eCode = pFound->eCode;
pToken->eEdge = pFound->eEdge;
return i;
}
pToken->n = i;
if( pik_find_class(pToken)!=0 ){
pToken->eType = T_CLASSNAME;
}else{
pToken->eType = T_ID;
}
return i;
}else if( c>='A' && c<='Z' ){
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){}
pToken->eType = T_PLACENAME;
return i;
}else if( c=='$' && z[1]>='1' && z[1]<='9' && !IsDigit(z[2]) ){
pToken->eType = T_PARAMETER;
pToken->eCode = z[1] - '1';
return 2;
}else if( c=='_' || c=='$' || c=='@' ){
for(i=1; (c = z[i])!=0 && (IsAlnum(c) || c=='_'); i++){}
pToken->eType = T_ID;
return i;
}else{
pToken->eType = T_ERROR;
return 1;
}
}
|
| ︙ | ︙ | |||
7812 7813 7814 7815 7816 7817 7818 |
if( z[i]==')' ){
args[nArg].n = i - iStart;
/* Remove leading and trailing whitespace from each argument.
** If what remains is one of $1, $2, ... $9 then transfer the
** corresponding argument from the outer context */
for(j=0; j<=nArg; j++){
PToken *t = &args[j];
| | | | 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 |
if( z[i]==')' ){
args[nArg].n = i - iStart;
/* Remove leading and trailing whitespace from each argument.
** If what remains is one of $1, $2, ... $9 then transfer the
** corresponding argument from the outer context */
for(j=0; j<=nArg; j++){
PToken *t = &args[j];
while( t->n>0 && IsSpace(t->z[0]) ){ t->n--; t->z++; }
while( t->n>0 && IsSpace(t->z[t->n-1]) ){ t->n--; }
if( t->n==2 && t->z[0]=='$' && t->z[1]>='1' && t->z[1]<='9' ){
if( pOuter ) *t = pOuter[t->z[1]-'1'];
else t->n = 0;
}
}
return i+1;
}
|
| ︙ | ︙ | |||
7894 7895 7896 7897 7898 7899 7900 |
pik_tokenize(p, &pMac->macroBody, pParser, args);
p->nCtx--;
pMac->inUse = 0;
}else{
#if 0
printf("******** Token %s (%d): \"%.*s\" **************\n",
yyTokenName[token.eType], token.eType,
| | > > > > > > > > > > > > > > > | 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 |
pik_tokenize(p, &pMac->macroBody, pParser, args);
p->nCtx--;
pMac->inUse = 0;
}else{
#if 0
printf("******** Token %s (%d): \"%.*s\" **************\n",
yyTokenName[token.eType], token.eType,
(int)(IsSpace(token.z[0]) ? 0 : sz), token.z);
#endif
token.n = (unsigned short)(sz & 0xffff);
if( p->nToken++ > PIKCHR_TOKEN_LIMIT ){
pik_error(p, &token, "script is too complex");
break;
}
if( token.eType==T_ISODATE ){
token.z = "\"" MANIFEST_ISODATE "\"";
token.n = sizeof(MANIFEST_ISODATE)+1;
token.eType = T_STRING;
}
pik_parser(pParser, token.eType, token);
}
}
}
/*
** Return the version name.
*/
const char *pikchr_version(void)
/* Emscripten workaround, else it chokes on the inlined version */;
const char *pikchr_version(void){
return RELEASE_VERSION " " MANIFEST_ISODATE;
}
/*
** Parse the PIKCHR script contained in zText[]. Return a rendering. Or
** if an error is encountered, return the error text. The error message
** is HTML formatted. So regardless of what happens, the return text
** is safe to be insertd into an HTML output stream.
**
|
| ︙ | ︙ | |||
8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 |
if( zHtmlHdr==0 ){
fprintf(stderr, "the \"%s\" option must come first\n",argv[i]);
exit(1);
}
bSvgOnly = 1;
mFlags |= PIKCHR_PLAINTEXT_ERRORS;
}else
{
fprintf(stderr,"unknown option: \"%s\"\n", argv[i]);
usage(argv[0]);
}
continue;
}
zIn = readFile(argv[i]);
| > > > > | 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 |
if( zHtmlHdr==0 ){
fprintf(stderr, "the \"%s\" option must come first\n",argv[i]);
exit(1);
}
bSvgOnly = 1;
mFlags |= PIKCHR_PLAINTEXT_ERRORS;
}else
if( strcmp(z,"version")==0 || strcmp(z,"v")==0 ){
printf("pikchr %s\n", pikchr_version());
return 0;
}else
{
fprintf(stderr,"unknown option: \"%s\"\n", argv[i]);
usage(argv[0]);
}
continue;
}
zIn = readFile(argv[i]);
|
| ︙ | ︙ | |||
8240 8241 8242 8243 8244 8245 8246 | return TCL_OK; } #endif /* PIKCHR_TCL */ | | | 8328 8329 8330 8331 8332 8333 8334 8335 | return TCL_OK; } #endif /* PIKCHR_TCL */ #line 8335 "pikchr.c" |
Changes to extsrc/pikchr.js.
1 2 |
var initPikchrModule = (() => {
| | | | > > > > > > > > > > > > > > | > | | | > > > > > > > > > > > > > | < | < < | | | | > | > > > | > | | > | | > > | | | > > > > > > | | | | | | | < < < < < < | < | | < < < < < < < < < < | | | < > | < < < | < > | | > > > > > > > | | | | | | | | | > > | | | > > > > > > > > < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | < | | > | | | | | < | > > > < < < < | < | > | < | | | | < | > | < | | | | > > > > > > > > > > > > > | < | < | < | < | | | | | | | | | | | | < | < | > > | | < | > > > > > > > > > > > > | | > > > | > > > > > > > > > > > > > > | > > | < < < < < < | < | | < < | | < | > | | > | > | | < < | | | | > > | | | | > | > > > > > > > > > > > > > > | | > | > > > > > > > > > > | > > | < | | < | | < | | > | > | > | > > > > | | < < < < < < < < < < < < < < | | | | < < < < > | < < < | | | < | | > | | | > > | | > > > > > > > > > > > > > > > > > | | | | > > > < | < | | > > < < | > | > > | > > < < < | | | | > > > > > > > > > > > > > > > > > > > > > > | | > | | > | < > | | > | | > | | > | < < < < > | < < < < < < | | | < < < < > < < < > > > > | < < > > > | > > > > > > > > > > > | | < > > > | > > > > > > > | < > > > | < | > > > | < < > | > > | < > > | | | < < | < < < > > > | < < < < < > > > > > > > > > > > | < < < < < > | | | < > > | > > > > > > > > > | | | | | | | | | | | | | | > | | | | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | | | | < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | < > > | | | | | < | | < < < < < < < < < | | > > | | < > | < < | | < > | | < > > > > > > > > > > | | > | < | | | > > | > | | | > | > > | | | | | | | | | | | | < | < | | | | | | | | | > > > > > > > | > < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 |
var initPikchrModule = (() => {
var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined;
return (
function(moduleArg = {}) {
var moduleRtn;
// include: shell.js
// The Module object: Our interface to the outside world. We import
// and export values on it. There are various ways Module can be used:
// 1. Not defined. We create it here
// 2. A function parameter, function(moduleArg) => Promise<Module>
// 3. pre-run appended it, var Module = {}; ..generated code..
// 4. External script tag defines var Module.
// We need to check if Module already exists (e.g. case 3 above).
// Substitution will be replaced with actual code on later stage of the build,
// this way Closure Compiler will not mangle it (e.g. case 4. above).
// Note that if you want to run closure, and also to use Module
// after the generated code, you will need to define var Module = {};
// before the code. Then that object will be used in the code, and you
// can continue to use Module afterwards as well.
var Module = moduleArg;
// Set up the promise that indicates the Module is initialized
var readyPromiseResolve, readyPromiseReject;
var readyPromise = new Promise((resolve, reject) => {
readyPromiseResolve = resolve;
readyPromiseReject = reject;
});
// Determine the runtime environment we are in. You can customize this by
// setting the ENVIRONMENT setting at compile time (see settings.js).
var ENVIRONMENT_IS_WEB = true;
var ENVIRONMENT_IS_WORKER = false;
// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
// Sometimes an existing Module object exists with properties
// meant to overwrite the default module functionality. Here
// we collect those properties and reapply _after_ we configure
// the current environment's defaults to avoid having to be so
// defensive during initialization.
var moduleOverrides = Object.assign({}, Module);
var arguments_ = [];
var thisProgram = "./this.program";
var quit_ = (status, toThrow) => {
throw toThrow;
};
// `/` should be present at the end if `scriptDirectory` is not empty
var scriptDirectory = "";
function locateFile(path) {
if (Module["locateFile"]) {
return Module["locateFile"](path, scriptDirectory);
}
return scriptDirectory + path;
}
// Hooks that are implemented differently in different runtime environments.
var readAsync, readBinary;
// Note that this includes Node.js workers when relevant (pthreads is enabled).
// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and
// ENVIRONMENT_IS_NODE.
if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
if (ENVIRONMENT_IS_WORKER) {
// Check worker, not web, since window could be polyfilled
scriptDirectory = self.location.href;
} else if (typeof document != "undefined" && document.currentScript) {
// web
scriptDirectory = document.currentScript.src;
}
// When MODULARIZE, this JS may be executed later, after document.currentScript
// is gone, so we saved it, and we use it here instead of any other info.
if (_scriptName) {
scriptDirectory = _scriptName;
}
// blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
// otherwise, slice off the final part of the url to find the script directory.
// if scriptDirectory does not contain a slash, lastIndexOf will return -1,
// and scriptDirectory will correctly be replaced with an empty string.
// If scriptDirectory contains a query (starting with ?) or a fragment (starting with #),
// they are removed because they could contain a slash.
if (scriptDirectory.startsWith("blob:")) {
scriptDirectory = "";
} else {
scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1);
}
{
// include: web_or_worker_shell_read.js
readAsync = url => fetch(url, {
credentials: "same-origin"
}).then(response => {
if (response.ok) {
return response.arrayBuffer();
}
return Promise.reject(new Error(response.status + " : " + response.url));
});
}
} else // end include: web_or_worker_shell_read.js
{}
var out = Module["print"] || console.log.bind(console);
var err = Module["printErr"] || console.error.bind(console);
// Merge back in the overrides
Object.assign(Module, moduleOverrides);
// Free the object hierarchy contained in the overrides, this lets the GC
// reclaim data used.
moduleOverrides = null;
// Emit code to handle expected values on the Module object. This applies Module.x
// to the proper local x. This has two benefits: first, we only emit it if it is
// expected to arrive, and second, by using a local everywhere else that can be
// minified.
if (Module["arguments"]) arguments_ = Module["arguments"];
if (Module["thisProgram"]) thisProgram = Module["thisProgram"];
// perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
// end include: shell.js
// include: preamble.js
// === Preamble library stuff ===
// Documentation for the public APIs defined in this file must be updated in:
// site/source/docs/api_reference/preamble.js.rst
// A prebuilt local version of the documentation is available at:
// site/build/text/docs/api_reference/preamble.js.txt
// You can also build docs locally as HTML or other formats in site/
// An online HTML version (which may be of a different version of Emscripten)
// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
var wasmBinary = Module["wasmBinary"];
// Wasm globals
var wasmMemory;
//========================================
// Runtime essentials
//========================================
// whether we are quitting the application. no code should run after this.
// set in exit() and abort()
var ABORT = false;
// set by exit() and abort(). Passed to 'onExit' handler.
// NOTE: This is also used as the process return code code in shell environments
// but only when noExitRuntime is false.
var EXITSTATUS;
// Memory management
var /** @type {!Int8Array} */ HEAP8, /** @type {!Uint8Array} */ HEAPU8, /** @type {!Int16Array} */ HEAP16, /** @type {!Uint16Array} */ HEAPU16, /** @type {!Int32Array} */ HEAP32, /** @type {!Uint32Array} */ HEAPU32, /** @type {!Float32Array} */ HEAPF32, /** @type {!Float64Array} */ HEAPF64;
// include: runtime_shared.js
function updateMemoryViews() {
var b = wasmMemory.buffer;
Module["HEAP8"] = HEAP8 = new Int8Array(b);
Module["HEAP16"] = HEAP16 = new Int16Array(b);
Module["HEAPU8"] = HEAPU8 = new Uint8Array(b);
Module["HEAPU16"] = HEAPU16 = new Uint16Array(b);
Module["HEAP32"] = HEAP32 = new Int32Array(b);
Module["HEAPU32"] = HEAPU32 = new Uint32Array(b);
Module["HEAPF32"] = HEAPF32 = new Float32Array(b);
Module["HEAPF64"] = HEAPF64 = new Float64Array(b);
}
// end include: runtime_shared.js
// include: runtime_stack_check.js
// end include: runtime_stack_check.js
var __ATPRERUN__ = [];
// functions called before the runtime is initialized
var __ATINIT__ = [];
// functions called during shutdown
var __ATPOSTRUN__ = [];
// functions called after the main() is called
var runtimeInitialized = false;
function preRun() {
var preRuns = Module["preRun"];
if (preRuns) {
if (typeof preRuns == "function") preRuns = [ preRuns ];
preRuns.forEach(addOnPreRun);
}
callRuntimeCallbacks(__ATPRERUN__);
}
function initRuntime() {
runtimeInitialized = true;
callRuntimeCallbacks(__ATINIT__);
}
function postRun() {
var postRuns = Module["postRun"];
if (postRuns) {
if (typeof postRuns == "function") postRuns = [ postRuns ];
postRuns.forEach(addOnPostRun);
}
callRuntimeCallbacks(__ATPOSTRUN__);
}
function addOnPreRun(cb) {
__ATPRERUN__.unshift(cb);
}
function addOnInit(cb) {
__ATINIT__.unshift(cb);
}
function addOnPostRun(cb) {
__ATPOSTRUN__.unshift(cb);
}
// include: runtime_math.js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc
// end include: runtime_math.js
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
// Module.preRun (used by emcc to add file preloading).
// Note that you can add dependencies in preRun, even though
// it happens right before run - run will be postponed until
// the dependencies are met.
var runDependencies = 0;
var runDependencyWatcher = null;
var dependenciesFulfilled = null;
function addRunDependency(id) {
runDependencies++;
Module["monitorRunDependencies"]?.(runDependencies);
}
function removeRunDependency(id) {
runDependencies--;
Module["monitorRunDependencies"]?.(runDependencies);
if (runDependencies == 0) {
if (runDependencyWatcher !== null) {
clearInterval(runDependencyWatcher);
runDependencyWatcher = null;
}
if (dependenciesFulfilled) {
var callback = dependenciesFulfilled;
dependenciesFulfilled = null;
callback();
}
}
}
/** @param {string|number=} what */ function abort(what) {
Module["onAbort"]?.(what);
what = "Aborted(" + what + ")";
// TODO(sbc): Should we remove printing and leave it up to whoever
// catches the exception?
err(what);
ABORT = true;
what += ". Build with -sASSERTIONS for more info.";
// Use a wasm runtime error, because a JS error might be seen as a foreign
// exception, which means we'd run destructors on it. We need the error to
// simply make the program stop.
// FIXME This approach does not work in Wasm EH because it currently does not assume
// all RuntimeErrors are from traps; it decides whether a RuntimeError is from
// a trap or not based on a hidden field within the object. So at the moment
// we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that
// allows this in the wasm spec.
// Suppress closure compiler warning here. Closure compiler's builtin extern
// definition for WebAssembly.RuntimeError claims it takes no arguments even
// though it can.
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed.
/** @suppress {checkTypes} */ var e = new WebAssembly.RuntimeError(what);
readyPromiseReject(e);
// Throw the error whether or not MODULARIZE is set because abort is used
// in code paths apart from instantiation where an exception is expected
// to be thrown when abort is called.
throw e;
}
// include: memoryprofiler.js
// end include: memoryprofiler.js
// include: URIUtils.js
// Prefix of data URIs emitted by SINGLE_FILE and related options.
var dataURIPrefix = "data:application/octet-stream;base64,";
/**
* Indicates whether filename is a base64 data URI.
* @noinline
*/ var isDataURI = filename => filename.startsWith(dataURIPrefix);
// end include: URIUtils.js
// include: runtime_exceptions.js
// end include: runtime_exceptions.js
function findWasmBinary() {
var f = "pikchr-v2813665466.wasm";
if (!isDataURI(f)) {
return locateFile(f);
}
return f;
}
var wasmBinaryFile;
function getBinarySync(file) {
if (file == wasmBinaryFile && wasmBinary) {
return new Uint8Array(wasmBinary);
}
if (readBinary) {
return readBinary(file);
}
throw "both async and sync fetching of the wasm failed";
}
function getBinaryPromise(binaryFile) {
// If we don't have the binary yet, load it asynchronously using readAsync.
if (!wasmBinary) {
// Fetch the binary using readAsync
return readAsync(binaryFile).then(response => new Uint8Array(/** @type{!ArrayBuffer} */ (response)), // Fall back to getBinarySync if readAsync fails
() => getBinarySync(binaryFile));
}
// Otherwise, getBinarySync should be able to get it synchronously
return Promise.resolve().then(() => getBinarySync(binaryFile));
}
function instantiateArrayBuffer(binaryFile, imports, receiver) {
return getBinaryPromise(binaryFile).then(binary => WebAssembly.instantiate(binary, imports)).then(receiver, reason => {
err(`failed to asynchronously prepare wasm: ${reason}`);
abort(reason);
});
}
function instantiateAsync(binary, binaryFile, imports, callback) {
if (!binary && typeof WebAssembly.instantiateStreaming == "function" && !isDataURI(binaryFile) && typeof fetch == "function") {
return fetch(binaryFile, {
credentials: "same-origin"
}).then(response => {
// Suppress closure warning here since the upstream definition for
// instantiateStreaming only allows Promise<Repsponse> rather than
// an actual Response.
// TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure is fixed.
/** @suppress {checkTypes} */ var result = WebAssembly.instantiateStreaming(response, imports);
return result.then(callback, function(reason) {
// We expect the most common failure cause to be a bad MIME type for the binary,
// in which case falling back to ArrayBuffer instantiation should work.
err(`wasm streaming compile failed: ${reason}`);
err("falling back to ArrayBuffer instantiation");
return instantiateArrayBuffer(binaryFile, imports, callback);
});
});
}
return instantiateArrayBuffer(binaryFile, imports, callback);
}
function getWasmImports() {
// prepare imports
return {
"a": wasmImports
};
}
// Create the wasm instance.
// Receives the wasm imports, returns the exports.
function createWasm() {
var info = getWasmImports();
// Load the wasm module and create an instance of using native support in the JS engine.
// handle a generated wasm instance, receiving its exports and
// performing other necessary setup
/** @param {WebAssembly.Module=} module*/ function receiveInstance(instance, module) {
wasmExports = instance.exports;
wasmMemory = wasmExports["d"];
updateMemoryViews();
addOnInit(wasmExports["e"]);
removeRunDependency("wasm-instantiate");
return wasmExports;
}
// wait for the pthread pool (if any)
addRunDependency("wasm-instantiate");
// Prefer streaming instantiation if available.
function receiveInstantiationResult(result) {
// 'result' is a ResultObject object which has both the module and instance.
// receiveInstance() will swap in the exports (to Module.asm) so they can be called
// TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
// When the regression is fixed, can restore the above PTHREADS-enabled path.
receiveInstance(result["instance"]);
}
// User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
// to manually instantiate the Wasm module themselves. This allows pages to
// run the instantiation parallel to any other async startup actions they are
// performing.
// Also pthreads and wasm workers initialize the wasm instance through this
// path.
if (Module["instantiateWasm"]) {
try {
return Module["instantiateWasm"](info, receiveInstance);
} catch (e) {
err(`Module.instantiateWasm callback failed with error: ${e}`);
// If instantiation fails, reject the module ready promise.
readyPromiseReject(e);
}
}
wasmBinaryFile ??= findWasmBinary();
// If instantiation fails, reject the module ready promise.
instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject);
return {};
}
// include: runtime_debug.js
// end include: runtime_debug.js
// === Body ===
// end include: preamble.js
/** @constructor */ function ExitStatus(status) {
this.name = "ExitStatus";
this.message = `Program terminated with exit(${status})`;
this.status = status;
}
var callRuntimeCallbacks = callbacks => {
// Pass the module as the first argument.
callbacks.forEach(f => f(Module));
};
/**
* @param {number} ptr
* @param {string} type
*/ function getValue(ptr, type = "i8") {
if (type.endsWith("*")) type = "*";
switch (type) {
case "i1":
return HEAP8[ptr];
case "i8":
return HEAP8[ptr];
case "i16":
return HEAP16[((ptr) >> 1)];
case "i32":
return HEAP32[((ptr) >> 2)];
case "i64":
abort("to do getValue(i64) use WASM_BIGINT");
case "float":
return HEAPF32[((ptr) >> 2)];
case "double":
return HEAPF64[((ptr) >> 3)];
case "*":
return HEAPU32[((ptr) >> 2)];
default:
abort(`invalid type for getValue: ${type}`);
}
}
var noExitRuntime = Module["noExitRuntime"] || true;
/**
* @param {number} ptr
* @param {number} value
* @param {string} type
*/ function setValue(ptr, value, type = "i8") {
if (type.endsWith("*")) type = "*";
switch (type) {
case "i1":
HEAP8[ptr] = value;
break;
case "i8":
HEAP8[ptr] = value;
break;
case "i16":
HEAP16[((ptr) >> 1)] = value;
break;
case "i32":
HEAP32[((ptr) >> 2)] = value;
break;
case "i64":
abort("to do setValue(i64) use WASM_BIGINT");
case "float":
HEAPF32[((ptr) >> 2)] = value;
break;
case "double":
HEAPF64[((ptr) >> 3)] = value;
break;
case "*":
HEAPU32[((ptr) >> 2)] = value;
break;
default:
abort(`invalid type for setValue: ${type}`);
}
}
var stackRestore = val => __emscripten_stack_restore(val);
var stackSave = () => _emscripten_stack_get_current();
var UTF8Decoder = typeof TextDecoder != "undefined" ? new TextDecoder : undefined;
/**
* Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given
* array that contains uint8 values, returns a copy of that string as a
* Javascript String object.
* heapOrArray is either a regular array, or a JavaScript typed array view.
* @param {number=} idx
* @param {number=} maxBytesToRead
* @return {string}
*/ var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => {
var endIdx = idx + maxBytesToRead;
var endPtr = idx;
// TextDecoder needs to know the byte length in advance, it doesn't stop on
// null terminator by itself. Also, use the length info to avoid running tiny
// strings through TextDecoder, since .subarray() allocates garbage.
// (As a tiny code save trick, compare endPtr against endIdx using a negation,
// so that undefined/NaN means Infinity)
while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr;
if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {
return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr));
}
var str = "";
// If building with TextDecoder, we have already computed the string length
// above, so test loop end condition against that
while (idx < endPtr) {
// For UTF8 byte structure, see:
// http://en.wikipedia.org/wiki/UTF-8#Description
// https://www.ietf.org/rfc/rfc2279.txt
// https://tools.ietf.org/html/rfc3629
var u0 = heapOrArray[idx++];
if (!(u0 & 128)) {
str += String.fromCharCode(u0);
continue;
}
var u1 = heapOrArray[idx++] & 63;
if ((u0 & 224) == 192) {
str += String.fromCharCode(((u0 & 31) << 6) | u1);
continue;
}
var u2 = heapOrArray[idx++] & 63;
if ((u0 & 240) == 224) {
u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
} else {
u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63);
}
if (u0 < 65536) {
str += String.fromCharCode(u0);
} else {
var ch = u0 - 65536;
str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023));
}
}
return str;
};
/**
* Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the
* emscripten HEAP, returns a copy of that string as a Javascript String object.
*
* @param {number} ptr
* @param {number=} maxBytesToRead - An optional length that specifies the
* maximum number of bytes to read. You can omit this parameter to scan the
* string until the first 0 byte. If maxBytesToRead is passed, and the string
* at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the
* string will cut short at that byte index (i.e. maxBytesToRead will not
* produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing
* frequent uses of UTF8ToString() with and without maxBytesToRead may throw
* JS JIT optimizations off, so it is worth to consider consistently using one
* @return {string}
*/ var UTF8ToString = (ptr, maxBytesToRead) => ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : "";
var ___assert_fail = (condition, filename, line, func) => {
abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [ filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function" ]);
};
var abortOnCannotGrowMemory = requestedSize => {
abort("OOM");
};
var _emscripten_resize_heap = requestedSize => {
var oldSize = HEAPU8.length;
// With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
requestedSize >>>= 0;
abortOnCannotGrowMemory(requestedSize);
};
var runtimeKeepaliveCounter = 0;
var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
var _proc_exit = code => {
EXITSTATUS = code;
if (!keepRuntimeAlive()) {
Module["onExit"]?.(code);
ABORT = true;
}
quit_(code, new ExitStatus(code));
};
/** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS = (status, implicit) => {
EXITSTATUS = status;
_proc_exit(status);
};
var _exit = exitJS;
var getCFunc = ident => {
var func = Module["_" + ident];
// closure exported function
return func;
};
var writeArrayToMemory = (array, buffer) => {
HEAP8.set(array, buffer);
};
var lengthBytesUTF8 = str => {
var len = 0;
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
// unit, not a Unicode code point of the character! So decode
// UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
var c = str.charCodeAt(i);
// possibly a lead surrogate
if (c <= 127) {
len++;
} else if (c <= 2047) {
len += 2;
} else if (c >= 55296 && c <= 57343) {
len += 4;
++i;
} else {
len += 3;
}
}
return len;
};
var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => {
// Parameter maxBytesToWrite is not optional. Negative values, 0, null,
// undefined and false each don't write out any bytes.
if (!(maxBytesToWrite > 0)) return 0;
var startIdx = outIdx;
var endIdx = outIdx + maxBytesToWrite - 1;
// -1 for string null terminator.
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code
// unit, not a Unicode code point of the character! So decode
// UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
// For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description
// and https://www.ietf.org/rfc/rfc2279.txt
// and https://tools.ietf.org/html/rfc3629
var u = str.charCodeAt(i);
// possibly a lead surrogate
if (u >= 55296 && u <= 57343) {
var u1 = str.charCodeAt(++i);
u = 65536 + ((u & 1023) << 10) | (u1 & 1023);
}
if (u <= 127) {
if (outIdx >= endIdx) break;
heap[outIdx++] = u;
} else if (u <= 2047) {
if (outIdx + 1 >= endIdx) break;
heap[outIdx++] = 192 | (u >> 6);
heap[outIdx++] = 128 | (u & 63);
} else if (u <= 65535) {
if (outIdx + 2 >= endIdx) break;
heap[outIdx++] = 224 | (u >> 12);
heap[outIdx++] = 128 | ((u >> 6) & 63);
heap[outIdx++] = 128 | (u & 63);
} else {
if (outIdx + 3 >= endIdx) break;
heap[outIdx++] = 240 | (u >> 18);
heap[outIdx++] = 128 | ((u >> 12) & 63);
heap[outIdx++] = 128 | ((u >> 6) & 63);
heap[outIdx++] = 128 | (u & 63);
}
}
// Null-terminate the pointer to the buffer.
heap[outIdx] = 0;
return outIdx - startIdx;
};
var stringToUTF8 = (str, outPtr, maxBytesToWrite) => stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
var stackAlloc = sz => __emscripten_stack_alloc(sz);
var stringToUTF8OnStack = str => {
var size = lengthBytesUTF8(str) + 1;
var ret = stackAlloc(size);
stringToUTF8(str, ret, size);
return ret;
};
/**
* @param {string|null=} returnType
* @param {Array=} argTypes
* @param {Arguments|Array=} args
* @param {Object=} opts
*/ var ccall = (ident, returnType, argTypes, args, opts) => {
// For fast lookup of conversion functions
var toC = {
"string": str => {
var ret = 0;
if (str !== null && str !== undefined && str !== 0) {
// null string
ret = stringToUTF8OnStack(str);
}
return ret;
},
"array": arr => {
var ret = stackAlloc(arr.length);
writeArrayToMemory(arr, ret);
return ret;
}
};
function convertReturnValue(ret) {
if (returnType === "string") {
return UTF8ToString(ret);
}
if (returnType === "boolean") return Boolean(ret);
return ret;
}
var func = getCFunc(ident);
var cArgs = [];
var stack = 0;
if (args) {
for (var i = 0; i < args.length; i++) {
var converter = toC[argTypes[i]];
if (converter) {
if (stack === 0) stack = stackSave();
cArgs[i] = converter(args[i]);
} else {
cArgs[i] = args[i];
}
}
}
var ret = func(...cArgs);
function onDone(ret) {
if (stack !== 0) stackRestore(stack);
return convertReturnValue(ret);
}
ret = onDone(ret);
return ret;
};
/**
* @param {string=} returnType
* @param {Array=} argTypes
* @param {Object=} opts
*/ var cwrap = (ident, returnType, argTypes, opts) => {
// When the function takes numbers and returns a number, we can just return
// the original function
var numericArgs = !argTypes || argTypes.every(type => type === "number" || type === "boolean");
var numericRet = returnType !== "string";
if (numericRet && numericArgs && !opts) {
return getCFunc(ident);
}
return (...args) => ccall(ident, returnType, argTypes, args, opts);
};
var wasmImports = {
/** @export */ a: ___assert_fail,
/** @export */ b: _emscripten_resize_heap,
/** @export */ c: _exit
};
var wasmExports = createWasm();
var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["e"])();
var _pikchr_version = Module["_pikchr_version"] = () => (_pikchr_version = Module["_pikchr_version"] = wasmExports["g"])();
var _pikchr = Module["_pikchr"] = (a0, a1, a2, a3, a4) => (_pikchr = Module["_pikchr"] = wasmExports["h"])(a0, a1, a2, a3, a4);
var __emscripten_stack_restore = a0 => (__emscripten_stack_restore = wasmExports["i"])(a0);
var __emscripten_stack_alloc = a0 => (__emscripten_stack_alloc = wasmExports["j"])(a0);
var _emscripten_stack_get_current = () => (_emscripten_stack_get_current = wasmExports["k"])();
// include: postamble.js
// === Auto-generated postamble setup entry stuff ===
Module["stackSave"] = stackSave;
Module["stackRestore"] = stackRestore;
Module["stackAlloc"] = stackAlloc;
Module["ccall"] = ccall;
Module["cwrap"] = cwrap;
Module["setValue"] = setValue;
Module["getValue"] = getValue;
var calledRun;
var calledPrerun;
dependenciesFulfilled = function runCaller() {
// If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
if (!calledRun) run();
if (!calledRun) dependenciesFulfilled = runCaller;
};
// try this again later, after new deps are fulfilled
function run() {
if (runDependencies > 0) {
return;
}
if (!calledPrerun) {
calledPrerun = 1;
preRun();
// a preRun added a dependency, run will be called later
if (runDependencies > 0) {
return;
}
}
function doRun() {
// run may have just been called through dependencies being fulfilled just in this very frame,
// or while the async setStatus time below was happening
if (calledRun) return;
calledRun = 1;
Module["calledRun"] = 1;
if (ABORT) return;
initRuntime();
readyPromiseResolve(Module);
Module["onRuntimeInitialized"]?.();
postRun();
}
if (Module["setStatus"]) {
Module["setStatus"]("Running...");
setTimeout(() => {
setTimeout(() => Module["setStatus"](""), 1);
doRun();
}, 1);
} else {
doRun();
}
}
if (Module["preInit"]) {
if (typeof Module["preInit"] == "function") Module["preInit"] = [ Module["preInit"] ];
while (Module["preInit"].length > 0) {
Module["preInit"].pop()();
}
}
run();
// end include: postamble.js
// include: postamble_modularize.js
// In MODULARIZE mode we wrap the generated code in a factory function
// and return either the Module itself, or a promise of the module.
// We assign to the `moduleRtn` global here and configure closure to see
// this as and extern so it won't get minified.
moduleRtn = readyPromise;
return moduleRtn;
}
);
})();
if (typeof exports === 'object' && typeof module === 'object')
module.exports = initPikchrModule;
else if (typeof define === 'function' && define['amd'])
define([], () => initPikchrModule);
|
Changes to extsrc/pikchr.wasm.
cannot compute difference between binary files
Changes to extsrc/shell.c.
| ︙ | ︙ | |||
232 233 234 235 236 237 238 239 240 241 242 243 244 245 | #define isatty(x) 1 #endif /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT #include <intrin.h> #endif #undef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN | > > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | #define isatty(x) 1 #endif /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) #define ToLower(X) (char)tolower((unsigned char)X) #define IsAlnum(X) isalnum((unsigned char)X) #define IsAlpha(X) isalpha((unsigned char)X) #if defined(_WIN32) || defined(WIN32) #if SQLITE_OS_WINRT #include <intrin.h> #endif #undef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN |
| ︙ | ︙ | |||
847 848 849 850 851 852 853 | */ static char *Argv0; /* ** Prompt strings. Initialized in main. Settable with ** .prompt main continue */ | | | 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | */ static char *Argv0; /* ** Prompt strings. Initialized in main. Settable with ** .prompt main continue */ #define PROMPT_LEN_MAX 128 /* First line prompt. default: "sqlite> " */ static char mainPrompt[PROMPT_LEN_MAX]; /* Continuation prompt. default: " ...> " */ static char continuePrompt[PROMPT_LEN_MAX]; /* This is variant of the standard-library strncpy() routine with the ** one change that the destination string is always zero-terminated, even |
| ︙ | ︙ | |||
1504 1505 1506 1507 1508 1509 1510 |
** that quoting is required.
**
** Return '"' if quoting is required. Return 0 if no quoting is required.
*/
static char quoteChar(const char *zName){
int i;
if( zName==0 ) return '"';
| | | | 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 |
** that quoting is required.
**
** Return '"' if quoting is required. Return 0 if no quoting is required.
*/
static char quoteChar(const char *zName){
int i;
if( zName==0 ) return '"';
if( !IsAlpha(zName[0]) && zName[0]!='_' ) return '"';
for(i=0; zName[i]; i++){
if( !IsAlnum(zName[i]) && zName[i]!='_' ) return '"';
}
return sqlite3_keyword_check(zName, i) ? '"' : 0;
}
/*
** Construct a fake object name and column list to describe the structure
** of the view, virtual table, or table valued function zSchema.zName.
|
| ︙ | ︙ | |||
2423 2424 2425 2426 2427 2428 2429 | ** Notice the ":" at the end of the prefix, which ** is needed to separate the prefix from the ** content in cases where the content starts ** with a digit. ** ** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed ** by the binary content of the blob. The "nnn" | | | 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 |
** Notice the ":" at the end of the prefix, which
** is needed to separate the prefix from the
** content in cases where the content starts
** with a digit.
**
** typeof(Y)='blob' The hash is taken over prefix "Bnnn:" followed
** by the binary content of the blob. The "nnn"
** in the prefix is the minimum-length decimal
** representation of the byte-length of the blob.
**
** According to the rules above, all of the following SELECT statements
** should return TRUE:
**
** SELECT sha3(1) = sha3('1');
**
|
| ︙ | ︙ | |||
3644 3645 3646 3647 3648 3649 3650 | ** ** This SQLite extension implements the UINT collating sequence. ** ** UINT works like BINARY for text, except that embedded strings ** of digits compare in numeric order. ** ** * Leading zeros are handled properly, in the sense that | | | 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 | ** ** This SQLite extension implements the UINT collating sequence. ** ** UINT works like BINARY for text, except that embedded strings ** of digits compare in numeric order. ** ** * Leading zeros are handled properly, in the sense that ** they do not mess of the magnitude comparison of embedded ** strings of digits. "x00123y" is equal to "x123y". ** ** * Only unsigned integers are recognized. Plus and minus ** signs are ignored. Decimal points and exponential notation ** are ignored. ** ** * Embedded integers can be of arbitrary length. Comparison |
| ︙ | ︙ | |||
3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 |
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(X) (void)(X)
#endif
/* A decimal object */
typedef struct Decimal Decimal;
struct Decimal {
char sign; /* 0 for positive, 1 for negative */
char oom; /* True if an OOM is encountered */
char isNull; /* True if holds a NULL rather than a number */
| > > > | 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 |
/* Mark a function parameter as unused, to suppress nuisance compiler
** warnings. */
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(X) (void)(X)
#endif
#ifndef IsSpace
#define IsSpace(X) isspace((unsigned char)X)
#endif
/* A decimal object */
typedef struct Decimal Decimal;
struct Decimal {
char sign; /* 0 for positive, 1 for negative */
char oom; /* True if an OOM is encountered */
char isNull; /* True if holds a NULL rather than a number */
|
| ︙ | ︙ | |||
3799 3800 3801 3802 3803 3804 3805 | p->oom = 0; p->isInit = 1; p->isNull = 0; p->nDigit = 0; p->nFrac = 0; p->a = sqlite3_malloc64( n+1 ); if( p->a==0 ) goto new_from_text_failed; | | | 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 |
p->oom = 0;
p->isInit = 1;
p->isNull = 0;
p->nDigit = 0;
p->nFrac = 0;
p->a = sqlite3_malloc64( n+1 );
if( p->a==0 ) goto new_from_text_failed;
for(i=0; IsSpace(zIn[i]); i++){}
if( zIn[i]=='-' ){
p->sign = 1;
i++;
}else if( zIn[i]=='+' ){
i++;
}
while( i<n && zIn[i]=='0' ) i++;
|
| ︙ | ︙ | |||
4454 4455 4456 4457 4458 4459 4460 |
decimal_add(pA, pB);
decimal_result(context, pA);
}
decimal_free(pA);
decimal_free(pB);
}
| | | 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 |
decimal_add(pA, pB);
decimal_result(context, pA);
}
decimal_free(pA);
decimal_free(pB);
}
/* Aggregate function: decimal_sum(X)
**
** Works like sum() except that it uses decimal arithmetic for unlimited
** precision.
*/
static void decimalSumStep(
sqlite3_context *context,
int argc,
|
| ︙ | ︙ | |||
4815 4816 4817 4818 4819 4820 4821 | if( bExact ) return -1; return iFirst; } /* ** Generate an error for a percentile function. ** | | | 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 |
if( bExact ) return -1;
return iFirst;
}
/*
** Generate an error for a percentile function.
**
** The error format string must have exactly one occurrence of "%%s()"
** (with two '%' characters). That substring will be replaced by the name
** of the function.
*/
static void percentError(sqlite3_context *pCtx, const char *zFormat, ...){
PercentileFunc *pFunc = (PercentileFunc*)sqlite3_user_data(pCtx);
char *zMsg1;
char *zMsg2;
|
| ︙ | ︙ | |||
5955 5956 5957 5958 5959 5960 5961 |
**
** Here is a query to show various boundry values for the binary64
** number format:
**
** WITH c(name,bin) AS (VALUES
** ('minimum positive value', x'0000000000000001'),
** ('maximum subnormal value', x'000fffffffffffff'),
| | | 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 |
**
** Here is a query to show various boundry values for the binary64
** number format:
**
** WITH c(name,bin) AS (VALUES
** ('minimum positive value', x'0000000000000001'),
** ('maximum subnormal value', x'000fffffffffffff'),
** ('minimum positive normal value', x'0010000000000000'),
** ('maximum value', x'7fefffffffffffff'))
** SELECT c.name, decimal_mul(ieee754_mantissa(c.bin),pow2.v)
** FROM pow2, c WHERE pow2.x=ieee754_exponent(c.bin);
**
*/
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
|
| ︙ | ︙ | |||
6342 6343 6344 6345 6346 6347 6348 |
ix -= mxI64;
/* With 2's complement ALU, this next can be 1 step, but is split into
* 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
smBase += (mxI64/2) * smStep;
smBase += (mxI64 - mxI64/2) * smStep;
}
/* Under UBSAN (or on 1's complement machines), must do this last term
| | | 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 |
ix -= mxI64;
/* With 2's complement ALU, this next can be 1 step, but is split into
* 2 for UBSAN's satisfaction (and hypothetical 1's complement ALUs.) */
smBase += (mxI64/2) * smStep;
smBase += (mxI64 - mxI64/2) * smStep;
}
/* Under UBSAN (or on 1's complement machines), must do this last term
* in steps to avoid the dreaded (and harmless) signed multiply overflow. */
if( ix>=2 ){
sqlite3_int64 ix2 = (sqlite3_int64)ix/2;
smBase += ix2*smStep;
ix -= ix2;
}
return smBase + ((sqlite3_int64)ix)*smStep;
}
|
| ︙ | ︙ | |||
6722 6723 6724 6725 6726 6727 6728 |
if( pCur->ss.iStep>0 ){
sqlite3_int64 szStep = pCur->ss.iStep;
if( pCur->ss.iBase<iMin ){
sqlite3_uint64 d = iMin - pCur->ss.iBase;
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm>iMax ){
| < | < | | 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 |
if( pCur->ss.iStep>0 ){
sqlite3_int64 szStep = pCur->ss.iStep;
if( pCur->ss.iBase<iMin ){
sqlite3_uint64 d = iMin - pCur->ss.iBase;
pCur->ss.iBase += ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm>iMax ){
pCur->ss.iTerm = iMax;
}
}else{
sqlite3_int64 szStep = -pCur->ss.iStep;
assert( szStep>0 );
if( pCur->ss.iBase>iMax ){
sqlite3_uint64 d = pCur->ss.iBase - iMax;
pCur->ss.iBase -= ((d+szStep-1)/szStep)*szStep;
}
if( pCur->ss.iTerm<iMin ){
pCur->ss.iTerm = iMin;
}
}
}
/* Apply LIMIT and OFFSET constraints, if any */
if( idxNum & 0x20 ){
if( iOffset>0 ){
|
| ︙ | ︙ | |||
9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 |
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* completion_vtab is a subclass of sqlite3_vtab which will
** serve as the underlying representation of a completion virtual table
*/
typedef struct completion_vtab completion_vtab;
struct completion_vtab {
sqlite3_vtab base; /* Base class - must be first */
| > > > > > | 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 |
/* #include "sqlite3ext.h" */
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <ctype.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
#ifndef IsAlnum
#define IsAlnum(X) isalnum((unsigned char)X)
#endif
/* completion_vtab is a subclass of sqlite3_vtab which will
** serve as the underlying representation of a completion virtual table
*/
typedef struct completion_vtab completion_vtab;
struct completion_vtab {
sqlite3_vtab base; /* Base class - must be first */
|
| ︙ | ︙ | |||
9359 9360 9361 9362 9363 9364 9365 |
if( pCur->nLine>0 ){
pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
if( pCur->zLine==0 ) return SQLITE_NOMEM;
}
}
if( pCur->zLine!=0 && pCur->zPrefix==0 ){
int i = pCur->nLine;
| | | 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 |
if( pCur->nLine>0 ){
pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg]));
if( pCur->zLine==0 ) return SQLITE_NOMEM;
}
}
if( pCur->zLine!=0 && pCur->zPrefix==0 ){
int i = pCur->nLine;
while( i>0 && (IsAlnum(pCur->zLine[i-1]) || pCur->zLine[i-1]=='_') ){
i--;
}
pCur->nPrefix = pCur->nLine - i;
if( pCur->nPrefix>0 ){
pCur->zPrefix = sqlite3_mprintf("%.*s", pCur->nPrefix, pCur->zLine + i);
if( pCur->zPrefix==0 ) return SQLITE_NOMEM;
}
|
| ︙ | ︙ | |||
14766 14767 14768 14769 14770 14771 14772 |
}
/* Register the auth callback with dbv */
if( rc==SQLITE_OK ){
sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
}
| | | 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 |
}
/* Register the auth callback with dbv */
if( rc==SQLITE_OK ){
sqlite3_set_authorizer(pNew->dbv, idxAuthCallback, (void*)pNew);
}
/* If an error has occurred, free the new object and return NULL. Otherwise,
** return the new sqlite3expert handle. */
if( rc!=SQLITE_OK ){
sqlite3_expert_destroy(pNew);
pNew = 0;
}
return pNew;
}
|
| ︙ | ︙ | |||
16288 16289 16290 16291 16292 16293 16294 |
**
** To enable all output (which is the default setting):
**
** PRAGMA vfstrace('+all');
**
** Individual APIs can be enabled or disabled by name, with or without
** the initial "x" character. For example, to set up for tracing lock
| | | 16296 16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 |
**
** To enable all output (which is the default setting):
**
** PRAGMA vfstrace('+all');
**
** Individual APIs can be enabled or disabled by name, with or without
** the initial "x" character. For example, to set up for tracing lock
** primitives only:
**
** PRAGMA vfstrace('-all, +Lock,Unlock,ShmLock');
**
** The argument to the vfstrace pragma ignores capitalization and any
** characters other than alphabetics, '+', and '-'.
*/
#include <stdlib.h>
|
| ︙ | ︙ | |||
18698 18699 18700 18701 18702 18703 18704 18705 18706 18707 18708 18709 18710 18711 | #endif int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*); /* typedef unsigned int u32; */ /* typedef unsigned char u8; */ /* typedef sqlite3_int64 i64; */ typedef struct RecoverTable RecoverTable; typedef struct RecoverColumn RecoverColumn; /* ** When recovering rows of data that can be associated with table ** definitions recovered from the sqlite_schema table, each table is ** represented by an instance of the following object. | > > > > > > > > > > | 18706 18707 18708 18709 18710 18711 18712 18713 18714 18715 18716 18717 18718 18719 18720 18721 18722 18723 18724 18725 18726 18727 18728 18729 | #endif int sqlite3_dbdata_init(sqlite3*, char**, const sqlite3_api_routines*); /* typedef unsigned int u32; */ /* typedef unsigned char u8; */ /* typedef sqlite3_int64 i64; */ /* ** Work around C99 "flex-array" syntax for pre-C99 compilers, so as ** to avoid complaints from -fsanitize=strict-bounds. */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define FLEXARRAY #else # define FLEXARRAY 1 #endif typedef struct RecoverTable RecoverTable; typedef struct RecoverColumn RecoverColumn; /* ** When recovering rows of data that can be associated with table ** definitions recovered from the sqlite_schema table, each table is ** represented by an instance of the following object. |
| ︙ | ︙ | |||
18805 18806 18807 18808 18809 18810 18811 |
** false if it is clear:
**
** (aElem[iKey/32] & (1 << (iKey%32))) ? 1 : 0
*/
typedef struct RecoverBitmap RecoverBitmap;
struct RecoverBitmap {
i64 nPg; /* Size of bitmap */
| | > > > | 18823 18824 18825 18826 18827 18828 18829 18830 18831 18832 18833 18834 18835 18836 18837 18838 18839 18840 18841 |
** false if it is clear:
**
** (aElem[iKey/32] & (1 << (iKey%32))) ? 1 : 0
*/
typedef struct RecoverBitmap RecoverBitmap;
struct RecoverBitmap {
i64 nPg; /* Size of bitmap */
u32 aElem[FLEXARRAY]; /* Array of 32-bit bitmasks */
};
/* Size in bytes of a RecoverBitmap object sufficient to cover 32 pages */
#define SZ_RECOVERBITMAP_32 (16)
/*
** State variables (part of the sqlite3_recover structure) used while
** recovering data for tables identified in the recovered schema (state
** RECOVER_STATE_WRITING).
*/
typedef struct RecoverStateW1 RecoverStateW1;
|
| ︙ | ︙ | |||
19047 19048 19049 19050 19051 19052 19053 |
**
** Otherwise, an attempt is made to allocate and return a bitmap object
** large enough to store a bit for all page numbers between 1 and nPg,
** inclusive. The bitmap is initially zeroed.
*/
static RecoverBitmap *recoverBitmapAlloc(sqlite3_recover *p, i64 nPg){
int nElem = (nPg+1+31) / 32;
| | | 19068 19069 19070 19071 19072 19073 19074 19075 19076 19077 19078 19079 19080 19081 19082 |
**
** Otherwise, an attempt is made to allocate and return a bitmap object
** large enough to store a bit for all page numbers between 1 and nPg,
** inclusive. The bitmap is initially zeroed.
*/
static RecoverBitmap *recoverBitmapAlloc(sqlite3_recover *p, i64 nPg){
int nElem = (nPg+1+31) / 32;
int nByte = SZ_RECOVERBITMAP_32 + nElem*sizeof(u32);
RecoverBitmap *pRet = (RecoverBitmap*)recoverMalloc(p, nByte);
if( pRet ){
pRet->nPg = nPg;
}
return pRet;
}
|
| ︙ | ︙ | |||
21239 21240 21241 21242 21243 21244 21245 |
** This function does the work of a single sqlite3_recover_step() call. It
** is guaranteed that the handle is not in an error state when this
** function is called.
*/
static void recoverStep(sqlite3_recover *p){
assert( p && p->errCode==SQLITE_OK );
switch( p->eState ){
| | > > < > > > > > > > > > | > | | | | | | | | | > > > | | < > > > | 21260 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 21278 21279 21280 21281 21282 21283 21284 21285 21286 21287 21288 21289 21290 21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 21303 21304 21305 21306 21307 21308 21309 21310 21311 21312 21313 21314 21315 21316 21317 21318 21319 21320 |
** This function does the work of a single sqlite3_recover_step() call. It
** is guaranteed that the handle is not in an error state when this
** function is called.
*/
static void recoverStep(sqlite3_recover *p){
assert( p && p->errCode==SQLITE_OK );
switch( p->eState ){
case RECOVER_STATE_INIT: {
int bUseWrapper = 1;
/* This is the very first call to sqlite3_recover_step() on this object.
*/
recoverSqlCallback(p, "BEGIN");
recoverSqlCallback(p, "PRAGMA writable_schema = on");
recoverSqlCallback(p, "PRAGMA foreign_keys = off");
recoverEnterMutex();
/* Open the output database. And register required virtual tables and
** user functions with the new handle. */
recoverOpenOutput(p);
/* Attempt to open a transaction and read page 1 of the input database.
** Two attempts may be made - one with a wrapper installed to ensure
** that the database header is sane, and then if that attempt returns
** SQLITE_NOTADB, then again with no wrapper. The second attempt is
** required for encrypted databases. */
if( p->errCode==SQLITE_OK ){
do{
p->errCode = SQLITE_OK;
if( bUseWrapper ) recoverInstallWrapper(p);
/* Open a transaction on the input database. */
sqlite3_file_control(p->dbIn, p->zDb, SQLITE_FCNTL_RESET_CACHE, 0);
recoverExec(p, p->dbIn, "PRAGMA writable_schema = on");
recoverExec(p, p->dbIn, "BEGIN");
if( p->errCode==SQLITE_OK ) p->bCloseTransaction = 1;
recoverExec(p, p->dbIn, "SELECT 1 FROM sqlite_schema");
recoverTransferSettings(p);
recoverOpenRecovery(p);
recoverCacheSchema(p);
if( bUseWrapper ) recoverUninstallWrapper(p);
}while( p->errCode==SQLITE_NOTADB
&& (bUseWrapper--)
&& SQLITE_OK==sqlite3_exec(p->dbIn, "ROLLBACK", 0, 0, 0)
);
}
recoverLeaveMutex();
recoverExec(p, p->dbOut, "BEGIN");
recoverWriteSchema1(p);
p->eState = RECOVER_STATE_WRITING;
break;
}
case RECOVER_STATE_WRITING: {
if( p->w1.pTbls==0 ){
recoverWriteDataInit(p);
}
if( SQLITE_DONE==recoverWriteDataStep(p) ){
recoverWriteDataCleanup(p);
|
| ︙ | ︙ | |||
21608 21609 21610 21611 21612 21613 21614 21615 21616 21617 21618 21619 21620 21621 | u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ u8 bSafeMode; /* True to prohibit unsafe operations */ u8 bSafeModePersist; /* The long-term value of bSafeMode */ u8 eRestoreState; /* See comments above doAutoDetectRestore() */ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */ ColModeOpts cmOpts; /* Option values affecting columnar mode output */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ int inputNesting; /* Track nesting level of .read and other redirects */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ int lineno; /* Line number of last line read from in */ | > | 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 21659 | u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ u8 eTraceType; /* SHELL_TRACE_* value for type of trace */ u8 bSafeMode; /* True to prohibit unsafe operations */ u8 bSafeModePersist; /* The long-term value of bSafeMode */ u8 eRestoreState; /* See comments above doAutoDetectRestore() */ u8 crlfMode; /* Do NL-to-CRLF translations when enabled (maybe) */ u8 eEscMode; /* Escape mode for text output */ ColModeOpts cmOpts; /* Option values affecting columnar mode output */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of vertical lines in the EQP output graph */ int inputNesting; /* Track nesting level of .read and other redirects */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ int lineno; /* Line number of last line read from in */ |
| ︙ | ︙ | |||
21708 21709 21710 21711 21712 21713 21714 21715 21716 21717 21718 21719 21720 21721 |
/* Bits in the ShellState.flgProgress variable */
#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
** callback limit is reached, and for each
** top-level SQL statement */
#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
/*
** These are the allowed shellFlgs values
*/
#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
| > > > > > > > > > | 21746 21747 21748 21749 21750 21751 21752 21753 21754 21755 21756 21757 21758 21759 21760 21761 21762 21763 21764 21765 21766 21767 21768 |
/* Bits in the ShellState.flgProgress variable */
#define SHELL_PROGRESS_QUIET 0x01 /* Omit announcing every progress callback */
#define SHELL_PROGRESS_RESET 0x02 /* Reset the count when the progress
** callback limit is reached, and for each
** top-level SQL statement */
#define SHELL_PROGRESS_ONCE 0x04 /* Cancel the --limit after firing once */
/* Allowed values for ShellState.eEscMode. The default value should
** be 0, so to change the default, reorder the names.
*/
#define SHELL_ESC_ASCII 0 /* Substitute ^Y for X where Y=X+0x40 */
#define SHELL_ESC_SYMBOL 1 /* Substitute U+2400 graphics */
#define SHELL_ESC_OFF 2 /* Send characters verbatim */
static const char *shell_EscModeNames[] = { "ascii", "symbol", "off" };
/*
** These are the allowed shellFlgs values
*/
#define SHFLG_Pagecache 0x00000001 /* The --pagecache option is used */
#define SHFLG_Lookaside 0x00000002 /* Lookaside memory is used */
#define SHFLG_Backslash 0x00000004 /* The --backslash option is used */
#define SHFLG_PreserveRowid 0x00000008 /* .dump preserves rowid values */
|
| ︙ | ︙ | |||
22045 22046 22047 22048 22049 22050 22051 | zStr[i*2] = '\0'; sqlite3_fprintf(out, "X'%s'", zStr); sqlite3_free(zStr); } /* | < | < | < | > | < < < < < < < < < < < | | < > | > | > > > | | | > > > > > > > > > > > > > > > > | > | | > > > > > > | < | | < > > > | > < | < | < | | < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < | < < | < < < < < < < < < | 22092 22093 22094 22095 22096 22097 22098 22099 22100 22101 22102 22103 22104 22105 22106 22107 22108 22109 22110 22111 22112 22113 22114 22115 22116 22117 22118 22119 22120 22121 22122 22123 22124 22125 22126 22127 22128 22129 22130 22131 22132 22133 22134 22135 22136 22137 22138 22139 22140 22141 22142 22143 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 22159 22160 22161 22162 22163 22164 22165 22166 22167 22168 22169 22170 22171 22172 22173 22174 22175 22176 22177 22178 22179 22180 22181 22182 22183 22184 22185 22186 22187 22188 22189 22190 22191 22192 22193 22194 22195 22196 22197 |
zStr[i*2] = '\0';
sqlite3_fprintf(out, "X'%s'", zStr);
sqlite3_free(zStr);
}
/*
** Output the given string as a quoted string using SQL quoting conventions:
**
** (1) Single quotes (') within the string are doubled
** (2) The whle string is enclosed in '...'
** (3) Control characters other than \n, \t, and \r\n are escaped
** using \u00XX notation and if such substitutions occur,
** the whole string is enclosed in unistr('...') instead of '...'.
**
** Step (3) is omitted if the control-character escape mode is OFF.
**
** See also: output_quoted_escaped_string() which does the same except
** that it does not make exceptions for \n, \t, and \r\n in step (3).
*/
static void output_quoted_string(ShellState *p, const char *zInX){
int i;
int needUnistr = 0;
int needDblQuote = 0;
const unsigned char *z = (const unsigned char*)zInX;
unsigned char c;
FILE *out = p->out;
sqlite3_fsetmode(out, _O_BINARY);
if( z==0 ) return;
for(i=0; (c = z[i])!=0; i++){
if( c=='\'' ){ needDblQuote = 1; }
if( c>0x1f ) continue;
if( c=='\t' || c=='\n' ) continue;
if( c=='\r' && z[i+1]=='\n' ) continue;
needUnistr = 1;
break;
}
if( (needDblQuote==0 && needUnistr==0)
|| (needDblQuote==0 && p->eEscMode==SHELL_ESC_OFF)
){
sqlite3_fprintf(out, "'%s'",z);
}else if( p->eEscMode==SHELL_ESC_OFF ){
char *zEncoded = sqlite3_mprintf("%Q", z);
sqlite3_fputs(zEncoded, out);
sqlite3_free(zEncoded);
}else{
if( needUnistr ){
sqlite3_fputs("unistr('", out);
}else{
sqlite3_fputs("'", out);
}
while( *z ){
for(i=0; (c = z[i])!=0; i++){
if( c=='\'' ) break;
if( c>0x1f ) continue;
if( c=='\t' || c=='\n' ) continue;
if( c=='\r' && z[i+1]=='\n' ) continue;
break;
}
if( i ){
sqlite3_fprintf(out, "%.*s", i, z);
z += i;
}
if( c==0 ) break;
if( c=='\'' ){
sqlite3_fputs("''", out);
}else{
sqlite3_fprintf(out, "\\u%04x", c);
}
z++;
}
if( needUnistr ){
sqlite3_fputs("')", out);
}else{
sqlite3_fputs("'", out);
}
}
setCrlfMode(p);
}
/*
** Output the given string as a quoted string using SQL quoting conventions.
** Additionallly , escape the "\n" and "\r" characters so that they do not
** get corrupted by end-of-line translation facilities in some operating
** systems.
**
** This is like output_quoted_string() but with the addition of the \r\n
** escape mechanism.
*/
static void output_quoted_escaped_string(ShellState *p, const char *z){
char *zEscaped;
sqlite3_fsetmode(p->out, _O_BINARY);
if( p->eEscMode==SHELL_ESC_OFF ){
zEscaped = sqlite3_mprintf("%Q", z);
}else{
zEscaped = sqlite3_mprintf("%#Q", z);
}
sqlite3_fputs(zEscaped, p->out);
sqlite3_free(zEscaped);
setCrlfMode(p);
}
/*
** Find earliest of chars within s specified in zAny.
** With ns == ~0, is like strpbrk(s,zAny) and s must be 0-terminated.
*/
|
| ︙ | ︙ | |||
22315 22316 22317 22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 |
}else{
ace[1] = (char)c;
sqlite3_fputs(ace+1, out);
}
}
sqlite3_fputs(zq, out);
}
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
static void output_html_string(FILE *out, const char *z){
int i;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 22332 22333 22334 22335 22336 22337 22338 22339 22340 22341 22342 22343 22344 22345 22346 22347 22348 22349 22350 22351 22352 22353 22354 22355 22356 22357 22358 22359 22360 22361 22362 22363 22364 22365 22366 22367 22368 22369 22370 22371 22372 22373 22374 22375 22376 22377 22378 22379 22380 22381 22382 22383 22384 22385 22386 22387 22388 22389 22390 22391 22392 22393 22394 22395 22396 22397 22398 22399 22400 22401 22402 22403 22404 22405 22406 22407 22408 22409 22410 22411 22412 22413 22414 22415 22416 22417 22418 22419 22420 22421 22422 22423 22424 22425 22426 22427 22428 22429 22430 22431 22432 |
}else{
ace[1] = (char)c;
sqlite3_fputs(ace+1, out);
}
}
sqlite3_fputs(zq, out);
}
/*
** Escape the input string if it is needed and in accordance with
** eEscMode.
**
** Escaping is needed if the string contains any control characters
** other than \t, \n, and \r\n
**
** If no escaping is needed (the common case) then set *ppFree to NULL
** and return the original string. If escapingn is needed, write the
** escaped string into memory obtained from sqlite3_malloc64() or the
** equivalent, and return the new string and set *ppFree to the new string
** as well.
**
** The caller is responsible for freeing *ppFree if it is non-NULL in order
** to reclaim memory.
*/
static const char *escapeOutput(
ShellState *p,
const char *zInX,
char **ppFree
){
i64 i, j;
i64 nCtrl = 0;
unsigned char *zIn;
unsigned char c;
unsigned char *zOut;
/* No escaping if disabled */
if( p->eEscMode==SHELL_ESC_OFF ){
*ppFree = 0;
return zInX;
}
/* Count the number of control characters in the string. */
zIn = (unsigned char*)zInX;
for(i=0; (c = zIn[i])!=0; i++){
if( c<=0x1f
&& c!='\t'
&& c!='\n'
&& (c!='\r' || zIn[i+1]!='\n')
){
nCtrl++;
}
}
if( nCtrl==0 ){
*ppFree = 0;
return zInX;
}
if( p->eEscMode==SHELL_ESC_SYMBOL ) nCtrl *= 2;
zOut = sqlite3_malloc64( i + nCtrl + 1 );
shell_check_oom(zOut);
for(i=j=0; (c = zIn[i])!=0; i++){
if( c>0x1f
|| c=='\t'
|| c=='\n'
|| (c=='\r' && zIn[i+1]=='\n')
){
continue;
}
if( i>0 ){
memcpy(&zOut[j], zIn, i);
j += i;
}
zIn += i+1;
i = -1;
switch( p->eEscMode ){
case SHELL_ESC_SYMBOL:
zOut[j++] = 0xe2;
zOut[j++] = 0x90;
zOut[j++] = 0x80+c;
break;
case SHELL_ESC_ASCII:
zOut[j++] = '^';
zOut[j++] = 0x40+c;
break;
}
}
if( i>0 ){
memcpy(&zOut[j], zIn, i);
j += i;
}
zOut[j] = 0;
*ppFree = (char*)zOut;
return (char*)zOut;
}
/*
** Output the given string with characters that are special to
** HTML escaped.
*/
static void output_html_string(FILE *out, const char *z){
int i;
|
| ︙ | ︙ | |||
22759 22760 22761 22762 22763 22764 22765 22766 |
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
for(i=0; i<nArg; i++){
sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
| > > > | > | 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882 |
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
int len = strlen30(azCol[i] ? azCol[i] : "");
if( len>w ) w = len;
}
if( p->cnt++>0 ) sqlite3_fputs(p->rowSeparator, p->out);
for(i=0; i<nArg; i++){
char *pFree = 0;
const char *pDisplay;
pDisplay = escapeOutput(p, azArg[i] ? azArg[i] : p->nullValue, &pFree);
sqlite3_fprintf(p->out, "%*s = %s%s", w, azCol[i],
pDisplay, p->rowSeparator);
if( pFree ) sqlite3_free(pFree);
}
break;
}
case MODE_ScanExp:
case MODE_Explain: {
static const int aExplainWidth[] = {4, 13, 4, 4, 4, 13, 2, 13};
static const int aExplainMap[] = {0, 1, 2, 3, 4, 5, 6, 7 };
|
| ︙ | ︙ | |||
22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849 22850 22851 |
case MODE_Pretty: { /* .schema and .fullschema with --indent */
char *z;
int j;
int nParen = 0;
char cEnd = 0;
char c;
int nLine = 0;
assert( nArg==1 );
if( azArg[0]==0 ) break;
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
){
sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
break;
}
z = sqlite3_mprintf("%s", azArg[0]);
shell_check_oom(z);
j = 0;
for(i=0; IsSpace(z[i]); i++){}
for(; (c = z[i])!=0; i++){
if( IsSpace(c) ){
if( z[j-1]=='\r' ) z[j-1] = '\n';
| > > > > | 22938 22939 22940 22941 22942 22943 22944 22945 22946 22947 22948 22949 22950 22951 22952 22953 22954 22955 22956 22957 22958 22959 22960 22961 22962 22963 |
case MODE_Pretty: { /* .schema and .fullschema with --indent */
char *z;
int j;
int nParen = 0;
char cEnd = 0;
char c;
int nLine = 0;
int isIndex;
int isWhere = 0;
assert( nArg==1 );
if( azArg[0]==0 ) break;
if( sqlite3_strlike("CREATE VIEW%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE TRIG%", azArg[0], 0)==0
){
sqlite3_fprintf(p->out, "%s;\n", azArg[0]);
break;
}
isIndex = sqlite3_strlike("CREATE INDEX%", azArg[0], 0)==0
|| sqlite3_strlike("CREATE UNIQUE INDEX%", azArg[0], 0)==0;
z = sqlite3_mprintf("%s", azArg[0]);
shell_check_oom(z);
j = 0;
for(i=0; IsSpace(z[i]); i++){}
for(; (c = z[i])!=0; i++){
if( IsSpace(c) ){
if( z[j-1]=='\r' ) z[j-1] = '\n';
|
| ︙ | ︙ | |||
22867 22868 22869 22870 22871 22872 22873 |
cEnd = ']';
}else if( c=='-' && z[i+1]=='-' ){
cEnd = '\n';
}else if( c=='(' ){
nParen++;
}else if( c==')' ){
nParen--;
| | > > > > > > > > > > > > > > > | > > > > | > | 22979 22980 22981 22982 22983 22984 22985 22986 22987 22988 22989 22990 22991 22992 22993 22994 22995 22996 22997 22998 22999 23000 23001 23002 23003 23004 23005 23006 23007 23008 23009 23010 23011 23012 23013 23014 23015 23016 23017 23018 23019 23020 23021 23022 23023 23024 23025 23026 23027 23028 23029 23030 23031 23032 23033 23034 23035 23036 23037 23038 23039 23040 23041 23042 23043 23044 23045 23046 |
cEnd = ']';
}else if( c=='-' && z[i+1]=='-' ){
cEnd = '\n';
}else if( c=='(' ){
nParen++;
}else if( c==')' ){
nParen--;
if( nLine>0 && nParen==0 && j>0 && !isWhere ){
printSchemaLineN(p->out, z, j, "\n");
j = 0;
}
}else if( (c=='w' || c=='W')
&& nParen==0 && isIndex
&& sqlite3_strnicmp("WHERE",&z[i],5)==0
&& !IsAlnum(z[i+5]) && z[i+5]!='_' ){
isWhere = 1;
}else if( isWhere && (c=='A' || c=='a')
&& nParen==0
&& sqlite3_strnicmp("AND",&z[i],3)==0
&& !IsAlnum(z[i+3]) && z[i+3]!='_' ){
printSchemaLineN(p->out, z, j, "\n ");
j = 0;
}
z[j++] = c;
if( nParen==1 && cEnd==0
&& (c=='(' || c=='\n' || (c==',' && !wsToEol(z+i+1)))
&& !isWhere
){
if( c=='\n' ) j--;
printSchemaLineN(p->out, z, j, "\n ");
j = 0;
nLine++;
while( IsSpace(z[i+1]) ){ i++; }
}
}
z[j] = 0;
}
printSchemaLine(p->out, z, ";\n");
sqlite3_free(z);
break;
}
case MODE_List: {
if( p->cnt++==0 && p->showHeader ){
for(i=0; i<nArg; i++){
char *z = azCol[i];
char *pFree;
const char *zOut = escapeOutput(p, z, &pFree);
sqlite3_fprintf(p->out, "%s%s", zOut,
i==nArg-1 ? p->rowSeparator : p->colSeparator);
if( pFree ) sqlite3_free(pFree);
}
}
if( azArg==0 ) break;
for(i=0; i<nArg; i++){
char *z = azArg[i];
char *pFree;
const char *zOut;
if( z==0 ) z = p->nullValue;
zOut = escapeOutput(p, z, &pFree);
sqlite3_fputs(zOut, p->out);
if( pFree ) sqlite3_free(pFree);
sqlite3_fputs((i<nArg-1)? p->colSeparator : p->rowSeparator, p->out);
}
break;
}
case MODE_Www:
case MODE_Html: {
if( p->cnt==0 && p->cMode==MODE_Www ){
|
| ︙ | ︙ | |||
24019 24020 24021 24022 24023 24024 24025 24026 24027 24028 24029 24030 24031 24032 |
** Compute characters to display on the first line of z[]. Stop at the
** first \r, \n, or \f. Expand \t into spaces. Return a copy (obtained
** from malloc()) of that first line, which caller should free sometime.
** Write anything to display on the next line into *pzTail. If this is
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
*/
static char *translateForDisplayAndDup(
const unsigned char *z, /* Input text to be transformed */
const unsigned char **pzTail, /* OUT: Tail of the input for next line */
int mxWidth, /* Max width. 0 means no limit */
u8 bWordWrap /* If true, avoid breaking mid-word */
){
int i; /* Input bytes consumed */
int j; /* Output bytes generated */
| > | 24151 24152 24153 24154 24155 24156 24157 24158 24159 24160 24161 24162 24163 24164 24165 |
** Compute characters to display on the first line of z[]. Stop at the
** first \r, \n, or \f. Expand \t into spaces. Return a copy (obtained
** from malloc()) of that first line, which caller should free sometime.
** Write anything to display on the next line into *pzTail. If this is
** the last line, write a NULL into *pzTail. (*pzTail is not allocated.)
*/
static char *translateForDisplayAndDup(
ShellState *p, /* To access current settings */
const unsigned char *z, /* Input text to be transformed */
const unsigned char **pzTail, /* OUT: Tail of the input for next line */
int mxWidth, /* Max width. 0 means no limit */
u8 bWordWrap /* If true, avoid breaking mid-word */
){
int i; /* Input bytes consumed */
int j; /* Output bytes generated */
|
| ︙ | ︙ | |||
24053 24054 24055 24056 24057 24058 24059 24060 24061 24062 24063 24064 24065 24066 24067 |
}
if( c>=' ' ){
n++;
i++;
j++;
continue;
}
if( c=='\t' ){
do{
n++;
j++;
}while( (n&7)!=0 && n<mxWidth );
i++;
continue;
}
| > < > > > | | | 24186 24187 24188 24189 24190 24191 24192 24193 24194 24195 24196 24197 24198 24199 24200 24201 24202 24203 24204 24205 24206 24207 24208 24209 24210 24211 24212 24213 24214 24215 24216 24217 24218 24219 24220 |
}
if( c>=' ' ){
n++;
i++;
j++;
continue;
}
if( c==0 || c=='\n' || (c=='\r' && z[i+1]=='\n') ) break;
if( c=='\t' ){
do{
n++;
j++;
}while( (n&7)!=0 && n<mxWidth );
i++;
continue;
}
n++;
j += 3;
i++;
}
if( n>=mxWidth && bWordWrap ){
/* Perhaps try to back up to a better place to break the line */
for(k=i; k>i/2; k--){
if( IsSpace(z[k-1]) ) break;
}
if( k<=i/2 ){
for(k=i; k>i/2; k--){
if( IsAlnum(z[k-1])!=IsAlnum(z[k]) && (z[k]&0xc0)!=0x80 ) break;
}
}
if( k<=i/2 ){
k = i;
}else{
i = k;
while( z[i]==' ' ) i++;
|
| ︙ | ︙ | |||
24108 24109 24110 24111 24112 24113 24114 24115 24116 24117 24118 24119 24120 24121 24122 |
continue;
}
if( c>=' ' ){
n++;
zOut[j++] = z[i++];
continue;
}
if( z[i]=='\t' ){
do{
n++;
zOut[j++] = ' ';
}while( (n&7)!=0 && n<mxWidth );
i++;
continue;
}
| > > > > > > | > > > > > > > > > > > > > > > > > > > | > | 24244 24245 24246 24247 24248 24249 24250 24251 24252 24253 24254 24255 24256 24257 24258 24259 24260 24261 24262 24263 24264 24265 24266 24267 24268 24269 24270 24271 24272 24273 24274 24275 24276 24277 24278 24279 24280 24281 24282 24283 24284 24285 24286 24287 24288 24289 24290 24291 24292 24293 24294 24295 24296 24297 24298 24299 24300 24301 24302 24303 24304 24305 24306 24307 24308 24309 24310 24311 24312 |
continue;
}
if( c>=' ' ){
n++;
zOut[j++] = z[i++];
continue;
}
if( c==0 ) break;
if( z[i]=='\t' ){
do{
n++;
zOut[j++] = ' ';
}while( (n&7)!=0 && n<mxWidth );
i++;
continue;
}
switch( p->eEscMode ){
case SHELL_ESC_SYMBOL:
zOut[j++] = 0xe2;
zOut[j++] = 0x90;
zOut[j++] = 0x80 + c;
break;
case SHELL_ESC_ASCII:
zOut[j++] = '^';
zOut[j++] = 0x40 + c;
break;
case SHELL_ESC_OFF:
zOut[j++] = c;
break;
}
i++;
}
zOut[j] = 0;
return (char*)zOut;
}
/* Return true if the text string z[] contains characters that need
** unistr() escaping.
*/
static int needUnistr(const unsigned char *z){
unsigned char c;
if( z==0 ) return 0;
while( (c = *z)>0x1f || c=='\t' || c=='\n' || (c=='\r' && z[1]=='\n') ){ z++; }
return c!=0;
}
/* Extract the value of the i-th current column for pStmt as an SQL literal
** value. Memory is obtained from sqlite3_malloc64() and must be freed by
** the caller.
*/
static char *quoted_column(sqlite3_stmt *pStmt, int i){
switch( sqlite3_column_type(pStmt, i) ){
case SQLITE_NULL: {
return sqlite3_mprintf("NULL");
}
case SQLITE_INTEGER:
case SQLITE_FLOAT: {
return sqlite3_mprintf("%s",sqlite3_column_text(pStmt,i));
}
case SQLITE_TEXT: {
const unsigned char *zText = sqlite3_column_text(pStmt,i);
return sqlite3_mprintf(needUnistr(zText)?"%#Q":"%Q",zText);
}
case SQLITE_BLOB: {
int j;
sqlite3_str *pStr = sqlite3_str_new(0);
const unsigned char *a = sqlite3_column_blob(pStmt,i);
int n = sqlite3_column_bytes(pStmt,i);
sqlite3_str_append(pStr, "x'", 2);
|
| ︙ | ︙ | |||
24228 24229 24230 24231 24232 24233 24234 |
int wx = p->colWidth[i];
if( wx==0 ){
wx = p->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
if( uz==0 ) uz = (u8*)"";
| | | 24390 24391 24392 24393 24394 24395 24396 24397 24398 24399 24400 24401 24402 24403 24404 |
int wx = p->colWidth[i];
if( wx==0 ){
wx = p->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
uz = (const unsigned char*)sqlite3_column_name(pStmt,i);
if( uz==0 ) uz = (u8*)"";
azData[i] = translateForDisplayAndDup(p, uz, &zNotUsed, wx, bw);
}
do{
int useNextLine = bNextLine;
bNextLine = 0;
if( (nRow+2)*nColumn >= nAlloc ){
nAlloc *= 2;
azData = sqlite3_realloc64(azData, nAlloc*sizeof(char*));
|
| ︙ | ︙ | |||
24252 24253 24254 24255 24256 24257 24258 24259 24260 24261 24262 24263 24264 24265 24266 |
wx = p->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
if( useNextLine ){
uz = azNextLine[i];
if( uz==0 ) uz = (u8*)zEmpty;
}else if( p->cmOpts.bQuote ){
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
}else{
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
if( uz==0 ) uz = (u8*)zShowNull;
}
azData[nRow*nColumn + i]
| > | | 24414 24415 24416 24417 24418 24419 24420 24421 24422 24423 24424 24425 24426 24427 24428 24429 24430 24431 24432 24433 24434 24435 24436 24437 |
wx = p->cmOpts.iWrap;
}
if( wx<0 ) wx = -wx;
if( useNextLine ){
uz = azNextLine[i];
if( uz==0 ) uz = (u8*)zEmpty;
}else if( p->cmOpts.bQuote ){
assert( azQuoted!=0 );
sqlite3_free(azQuoted[i]);
azQuoted[i] = quoted_column(pStmt,i);
uz = (const unsigned char*)azQuoted[i];
}else{
uz = (const unsigned char*)sqlite3_column_text(pStmt,i);
if( uz==0 ) uz = (u8*)zShowNull;
}
azData[nRow*nColumn + i]
= translateForDisplayAndDup(p, uz, &azNextLine[i], wx, bw);
if( azNextLine[i] ){
bNextLine = 1;
abRowDiv[nRow-1] = 0;
bMultiLineRowExists = 1;
}
}
}while( bNextLine || sqlite3_step(pStmt)==SQLITE_ROW );
|
| ︙ | ︙ | |||
25183 25184 25185 25186 25187 25188 25189 | ".load FILE ?ENTRY? Load an extension library", #endif #if !defined(SQLITE_SHELL_FIDDLE) ".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout", #else ".log on|off Turn logging on or off.", #endif | | > | 25346 25347 25348 25349 25350 25351 25352 25353 25354 25355 25356 25357 25358 25359 25360 25361 25362 25363 25364 25365 25366 25367 25368 25369 25370 25371 25372 25373 25374 25375 25376 25377 25378 | ".load FILE ?ENTRY? Load an extension library", #endif #if !defined(SQLITE_SHELL_FIDDLE) ".log FILE|on|off Turn logging on or off. FILE can be stderr/stdout", #else ".log on|off Turn logging on or off.", #endif ".mode ?MODE? ?OPTIONS? Set output mode", " MODE is one of:", " ascii Columns/rows delimited by 0x1F and 0x1E", " box Tables using unicode box-drawing characters", " csv Comma-separated values", " column Output in columns. (See .width)", " html HTML <table> code", " insert SQL insert statements for TABLE", " json Results in a JSON array", " line One value per line", " list Values delimited by \"|\"", " markdown Markdown table format", " qbox Shorthand for \"box --wrap 60 --quote\"", " quote Escape answers as for SQL", " table ASCII-art table", " tabs Tab-separated values", " tcl TCL list elements", " OPTIONS: (for columnar modes or insert mode):", " --escape T ctrl-char escape; T is one of: symbol, ascii, off", " --wrap N Wrap output lines to no longer than N characters", " --wordwrap B Wrap or not at word boundaries per B (on/off)", " --ww Shorthand for \"--wordwrap 1\"", " --quote Quote output text as SQL literals", " --noquote Do not quote output text", " TABLE The name of SQL table used for \"insert\" mode", #ifndef SQLITE_SHELL_FIDDLE |
| ︙ | ︙ | |||
25976 25977 25978 25979 25980 25981 25982 | char zBuf[1000]; #if HAVE_LINENOISE==2 UNUSED_PARAMETER(pUserData); #endif if( nLine>(i64)sizeof(zBuf)-30 ) return; if( zLine[0]=='.' || zLine[0]=='#') return; | | | 26140 26141 26142 26143 26144 26145 26146 26147 26148 26149 26150 26151 26152 26153 26154 |
char zBuf[1000];
#if HAVE_LINENOISE==2
UNUSED_PARAMETER(pUserData);
#endif
if( nLine>(i64)sizeof(zBuf)-30 ) return;
if( zLine[0]=='.' || zLine[0]=='#') return;
for(i=nLine-1; i>=0 && (IsAlnum(zLine[i]) || zLine[i]=='_'); i--){}
if( i==nLine-1 ) return;
iStart = i+1;
memcpy(zBuf, zLine, iStart);
zSql = sqlite3_mprintf("SELECT DISTINCT candidate COLLATE nocase"
" FROM completion(%Q,%Q) ORDER BY 1",
&zLine[iStart], zLine);
shell_check_oom(zSql);
|
| ︙ | ︙ | |||
28216 28217 28218 28219 28220 28221 28222 28223 28224 28225 28226 28227 28228 28229 |
);
sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
sqlite3_recover_run(p);
if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
const char *zErr = sqlite3_recover_errmsg(p);
int errCode = sqlite3_recover_errcode(p);
sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
}
rc = sqlite3_recover_finish(p);
| > | 28380 28381 28382 28383 28384 28385 28386 28387 28388 28389 28390 28391 28392 28393 28394 |
);
sqlite3_recover_config(p, 789, (void*)zRecoveryDb); /* Debug use only */
sqlite3_recover_config(p, SQLITE_RECOVER_LOST_AND_FOUND, (void*)zLAF);
sqlite3_recover_config(p, SQLITE_RECOVER_ROWIDS, (void*)&bRowids);
sqlite3_recover_config(p, SQLITE_RECOVER_FREELIST_CORRUPT,(void*)&bFreelist);
sqlite3_fprintf(pState->out, ".dbconfig defensive off\n");
sqlite3_recover_run(p);
if( sqlite3_recover_errcode(p)!=SQLITE_OK ){
const char *zErr = sqlite3_recover_errmsg(p);
int errCode = sqlite3_recover_errcode(p);
sqlite3_fprintf(stderr,"sql error: %s (%d)\n", zErr, errCode);
}
rc = sqlite3_recover_finish(p);
|
| ︙ | ︙ | |||
29941 29942 29943 29944 29945 29946 29947 29948 29949 29950 29951 29952 29953 29954 29955 29956 29957 29958 29959 29960 29961 29962 29963 29964 29965 29966 29967 29968 29969 29970 29971 29972 29973 29974 29975 29976 29977 29978 29979 29980 29981 29982 29983 29984 29985 29986 29987 29988 |
}
}else
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
ColModeOpts cmOpts = ColModeOpts_default;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( optionMatch(z,"wrap") && i+1<nArg ){
cmOpts.iWrap = integerValue(azArg[++i]);
}else if( optionMatch(z,"ww") ){
cmOpts.bWordWrap = 1;
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
}else if( optionMatch(z,"quote") ){
cmOpts.bQuote = 1;
}else if( optionMatch(z,"noquote") ){
cmOpts.bQuote = 0;
}else if( zMode==0 ){
zMode = z;
/* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
cmOpts = cmo;
}
}else if( zTabname==0 ){
zTabname = z;
}else if( z[0]=='-' ){
sqlite3_fprintf(stderr,"unknown option: %s\n", z);
eputz("options:\n"
" --noquote\n"
" --quote\n"
" --wordwrap on/off\n"
" --wrap N\n"
" --ww\n");
rc = 1;
goto meta_command_exit;
}else{
sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > | > > | > > > > > > | 30106 30107 30108 30109 30110 30111 30112 30113 30114 30115 30116 30117 30118 30119 30120 30121 30122 30123 30124 30125 30126 30127 30128 30129 30130 30131 30132 30133 30134 30135 30136 30137 30138 30139 30140 30141 30142 30143 30144 30145 30146 30147 30148 30149 30150 30151 30152 30153 30154 30155 30156 30157 30158 30159 30160 30161 30162 30163 30164 30165 30166 30167 30168 30169 30170 30171 30172 30173 30174 30175 30176 30177 30178 30179 30180 30181 30182 30183 30184 30185 30186 30187 30188 30189 30190 30191 30192 30193 30194 30195 30196 30197 30198 30199 30200 30201 30202 30203 30204 30205 30206 30207 30208 30209 30210 30211 30212 |
}
}else
if( c=='m' && cli_strncmp(azArg[0], "mode", n)==0 ){
const char *zMode = 0;
const char *zTabname = 0;
int i, n2;
int chng = 0; /* 0x01: change to cmopts. 0x02: Any other change */
ColModeOpts cmOpts = ColModeOpts_default;
for(i=1; i<nArg; i++){
const char *z = azArg[i];
if( optionMatch(z,"wrap") && i+1<nArg ){
cmOpts.iWrap = integerValue(azArg[++i]);
chng |= 1;
}else if( optionMatch(z,"ww") ){
cmOpts.bWordWrap = 1;
chng |= 1;
}else if( optionMatch(z,"wordwrap") && i+1<nArg ){
cmOpts.bWordWrap = (u8)booleanValue(azArg[++i]);
chng |= 1;
}else if( optionMatch(z,"quote") ){
cmOpts.bQuote = 1;
chng |= 1;
}else if( optionMatch(z,"noquote") ){
cmOpts.bQuote = 0;
chng |= 1;
}else if( optionMatch(z,"escape") && i+1<nArg ){
/* See similar code at tag-20250224-1 */
const char *zEsc = azArg[++i];
int k;
for(k=0; k<ArraySize(shell_EscModeNames); k++){
if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
p->eEscMode = k;
chng |= 2;
break;
}
}
if( k>=ArraySize(shell_EscModeNames) ){
sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
" - choices:", zEsc);
for(k=0; k<ArraySize(shell_EscModeNames); k++){
sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
}
sqlite3_fprintf(stderr, "\n");
rc = 1;
goto meta_command_exit;
}
}else if( zMode==0 ){
zMode = z;
/* Apply defaults for qbox pseudo-mode. If that
* overwrites already-set values, user was informed of this.
*/
chng |= 1;
if( cli_strcmp(z, "qbox")==0 ){
ColModeOpts cmo = ColModeOpts_default_qbox;
zMode = "box";
cmOpts = cmo;
}
}else if( zTabname==0 ){
zTabname = z;
}else if( z[0]=='-' ){
sqlite3_fprintf(stderr,"unknown option: %s\n", z);
eputz("options:\n"
" --escape MODE\n"
" --noquote\n"
" --quote\n"
" --wordwrap on/off\n"
" --wrap N\n"
" --ww\n");
rc = 1;
goto meta_command_exit;
}else{
sqlite3_fprintf(stderr,"extra argument: \"%s\"\n", z);
rc = 1;
goto meta_command_exit;
}
}
if( !chng ){
if( p->mode==MODE_Column
|| (p->mode>=MODE_Markdown && p->mode<=MODE_Box)
){
sqlite3_fprintf(p->out,
"current output mode: %s --wrap %d --wordwrap %s "
"--%squote --escape %s\n",
modeDescr[p->mode], p->cmOpts.iWrap,
p->cmOpts.bWordWrap ? "on" : "off",
p->cmOpts.bQuote ? "" : "no",
shell_EscModeNames[p->eEscMode]
);
}else{
sqlite3_fprintf(p->out,
"current output mode: %s --escape %s\n",
modeDescr[p->mode],
shell_EscModeNames[p->eEscMode]
);
}
}
if( zMode==0 ){
zMode = modeDescr[p->mode];
if( (chng&1)==0 ) cmOpts = p->cmOpts;
}
n2 = strlen30(zMode);
if( cli_strncmp(zMode,"lines",n2)==0 ){
p->mode = MODE_Line;
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"columns",n2)==0 ){
p->mode = MODE_Column;
|
| ︙ | ︙ | |||
30028 30029 30030 30031 30032 30033 30034 30035 30036 30037 30038 30039 30040 30041 |
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
}else if( cli_strncmp(zMode,"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
| > > > > > | 30231 30232 30233 30234 30235 30236 30237 30238 30239 30240 30241 30242 30243 30244 30245 30246 30247 30248 30249 |
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
}else if( cli_strncmp(zMode,"tabs",n2)==0 ){
p->mode = MODE_List;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Tab);
}else if( cli_strncmp(zMode,"insert",n2)==0 ){
p->mode = MODE_Insert;
set_table_name(p, zTabname ? zTabname : "table");
if( p->eEscMode==SHELL_ESC_OFF ){
ShellSetFlag(p, SHFLG_Newlines);
}else{
ShellClearFlag(p, SHFLG_Newlines);
}
}else if( cli_strncmp(zMode,"quote",n2)==0 ){
p->mode = MODE_Quote;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_Row);
}else if( cli_strncmp(zMode,"ascii",n2)==0 ){
p->mode = MODE_Ascii;
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Unit);
|
| ︙ | ︙ | |||
32264 32265 32266 32267 32268 32269 32270 | } /* ** The CLI needs a working sqlite3_complete() to work properly. So error ** out of the build if compiling with SQLITE_OMIT_COMPLETE. */ #ifdef SQLITE_OMIT_COMPLETE | | | 32472 32473 32474 32475 32476 32477 32478 32479 32480 32481 32482 32483 32484 32485 32486 |
}
/*
** The CLI needs a working sqlite3_complete() to work properly. So error
** out of the build if compiling with SQLITE_OMIT_COMPLETE.
*/
#ifdef SQLITE_OMIT_COMPLETE
# error the CLI application is incompatible with SQLITE_OMIT_COMPLETE.
#endif
/*
** Return true if zSql is a complete SQL statement. Return false if it
** ends in the middle of a string literal or C-style comment.
*/
static int line_is_complete(char *zSql, int nSql){
|
| ︙ | ︙ | |||
32443 32444 32445 32446 32447 32448 32449 |
i64 nZ = 0;
UNUSED_PARAMETER(in);
UNUSED_PARAMETER(isContinuation);
if(!z || !*z){
return 0;
}
| | | 32651 32652 32653 32654 32655 32656 32657 32658 32659 32660 32661 32662 32663 32664 32665 |
i64 nZ = 0;
UNUSED_PARAMETER(in);
UNUSED_PARAMETER(isContinuation);
if(!z || !*z){
return 0;
}
while(*z && IsSpace(*z)) ++z;
zBegin = z;
for(; *z && '\n'!=*z; ++nZ, ++z){}
if(nZ>0 && '\r'==zBegin[nZ-1]){
--nZ;
}
shellState.wasm.zPos = z;
zLine = realloc(zPrior, nZ+1);
|
| ︙ | ︙ | |||
32748 32749 32750 32751 32752 32753 32754 32755 32756 32757 32758 32759 32760 32761 | " -column set output mode to 'column'\n" " -cmd COMMAND run \"COMMAND\" before reading stdin\n" " -csv set output mode to 'csv'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) " -deserialize open the database using sqlite3_deserialize()\n" #endif " -echo print inputs before execution\n" " -init FILENAME read/process named file\n" " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) " -heap SIZE Size of heap for memsys3 or memsys5\n" #endif " -help show this message\n" " -html set output mode to HTML\n" | > | 32956 32957 32958 32959 32960 32961 32962 32963 32964 32965 32966 32967 32968 32969 32970 | " -column set output mode to 'column'\n" " -cmd COMMAND run \"COMMAND\" before reading stdin\n" " -csv set output mode to 'csv'\n" #if !defined(SQLITE_OMIT_DESERIALIZE) " -deserialize open the database using sqlite3_deserialize()\n" #endif " -echo print inputs before execution\n" " -escape T ctrl-char escape; T is one of: symbol, ascii, off\n" " -init FILENAME read/process named file\n" " -[no]header turn headers on or off\n" #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5) " -heap SIZE Size of heap for memsys3 or memsys5\n" #endif " -help show this message\n" " -html set output mode to HTML\n" |
| ︙ | ︙ | |||
32795 32796 32797 32798 32799 32800 32801 |
" -vfs NAME use NAME as the default VFS\n"
" -vfstrace enable tracing of all VFS calls\n"
#ifdef SQLITE_HAVE_ZLIB
" -zip open the file as a ZIP Archive\n"
#endif
;
static void usage(int showDetail){
| | | 33004 33005 33006 33007 33008 33009 33010 33011 33012 33013 33014 33015 33016 33017 33018 |
" -vfs NAME use NAME as the default VFS\n"
" -vfstrace enable tracing of all VFS calls\n"
#ifdef SQLITE_HAVE_ZLIB
" -zip open the file as a ZIP Archive\n"
#endif
;
static void usage(int showDetail){
sqlite3_fprintf(stderr,"Usage: %s [OPTIONS] [FILENAME [SQL...]]\n"
"FILENAME is the name of an SQLite database. A new database is created\n"
"if the file does not previously exist. Defaults to :memory:.\n", Argv0);
if( showDetail ){
sqlite3_fprintf(stderr,"OPTIONS include:\n%s", zOptions);
}else{
eputz("Use the -help option for additional information\n");
}
|
| ︙ | ︙ | |||
33181 33182 33183 33184 33185 33186 33187 33188 33189 33190 33191 33192 33193 33194 |
}else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(cmdline_option_value(argc, argv, ++i));
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}
}
#ifndef SQLITE_SHELL_FIDDLE
if( !bEnableVfstrace ) verify_uninitialized();
#endif
| > > > | 33390 33391 33392 33393 33394 33395 33396 33397 33398 33399 33400 33401 33402 33403 33404 33405 33406 |
}else if( cli_strcmp(z,"-nonce")==0 ){
free(data.zNonce);
data.zNonce = strdup(cmdline_option_value(argc, argv, ++i));
}else if( cli_strcmp(z,"-unsafe-testing")==0 ){
ShellSetFlag(&data,SHFLG_TestingMode);
}else if( cli_strcmp(z,"-safe")==0 ){
/* no-op - catch this on the second pass */
}else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
/* skip over the argument */
i++;
}
}
#ifndef SQLITE_SHELL_FIDDLE
if( !bEnableVfstrace ) verify_uninitialized();
#endif
|
| ︙ | ︙ | |||
33280 33281 33282 33283 33284 33285 33286 33287 33288 33289 33290 33291 33292 33293 |
}else if( cli_strcmp(z,"-table")==0 ){
data.mode = MODE_Table;
}else if( cli_strcmp(z,"-box")==0 ){
data.mode = MODE_Box;
}else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
| > > > > > > > > > > > > > > > > > > > | 33492 33493 33494 33495 33496 33497 33498 33499 33500 33501 33502 33503 33504 33505 33506 33507 33508 33509 33510 33511 33512 33513 33514 33515 33516 33517 33518 33519 33520 33521 33522 33523 33524 |
}else if( cli_strcmp(z,"-table")==0 ){
data.mode = MODE_Table;
}else if( cli_strcmp(z,"-box")==0 ){
data.mode = MODE_Box;
}else if( cli_strcmp(z,"-csv")==0 ){
data.mode = MODE_Csv;
memcpy(data.colSeparator,",",2);
}else if( cli_strcmp(z,"-escape")==0 && i+1<argc ){
/* See similar code at tag-20250224-1 */
const char *zEsc = argv[++i];
int k;
for(k=0; k<ArraySize(shell_EscModeNames); k++){
if( sqlite3_stricmp(zEsc,shell_EscModeNames[k])==0 ){
data.eEscMode = k;
break;
}
}
if( k>=ArraySize(shell_EscModeNames) ){
sqlite3_fprintf(stderr, "unknown control character escape mode \"%s\""
" - choices:", zEsc);
for(k=0; k<ArraySize(shell_EscModeNames); k++){
sqlite3_fprintf(stderr, " %s", shell_EscModeNames[k]);
}
sqlite3_fprintf(stderr, "\n");
exit(1);
}
#ifdef SQLITE_HAVE_ZLIB
}else if( cli_strcmp(z,"-zip")==0 ){
data.openMode = SHELL_OPEN_ZIPFILE;
#endif
}else if( cli_strcmp(z,"-append")==0 ){
data.openMode = SHELL_OPEN_APPENDVFS;
#ifndef SQLITE_OMIT_DESERIALIZE
|
| ︙ | ︙ | |||
33441 33442 33443 33444 33445 33446 33447 33448 33449 33450 33451 33452 33453 33454 33455 |
if( !readStdin ){
/* Run all arguments that do not begin with '-' as if they were separate
** command-line inputs, except for the argToSkip argument which contains
** the database filename.
*/
for(i=0; i<nCmd; i++){
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ){
if( rc==2 ) rc = 0;
goto shell_main_exit;
}
}else{
open_db(&data, 0);
| > < | 33672 33673 33674 33675 33676 33677 33678 33679 33680 33681 33682 33683 33684 33685 33686 33687 33688 33689 33690 33691 33692 33693 33694 |
if( !readStdin ){
/* Run all arguments that do not begin with '-' as if they were separate
** command-line inputs, except for the argToSkip argument which contains
** the database filename.
*/
for(i=0; i<nCmd; i++){
echo_group_input(&data, azCmd[i]);
if( azCmd[i][0]=='.' ){
rc = do_meta_command(azCmd[i], &data);
if( rc ){
if( rc==2 ) rc = 0;
goto shell_main_exit;
}
}else{
open_db(&data, 0);
rc = shell_exec(&data, azCmd[i], &zErrMsg);
if( zErrMsg || rc ){
if( zErrMsg!=0 ){
shellEmitError(zErrMsg);
}else{
sqlite3_fprintf(stderr,
"Error: unable to process SQL: %s\n", azCmd[i]);
|
| ︙ | ︙ |
Changes to extsrc/sqlite3.c.
| ︙ | ︙ | |||
14 15 16 17 18 19 20 | ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** the text of this file. Search for "Begin file sqlite3.h" to find the start ** of the embedded sqlite3.h header file.) Additional code files may be needed ** if you want a wrapper to interface SQLite with your choice of programming ** language. The code for the "sqlite3" command-line shell is also in a ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in ** 18bda13e197e4b4ec7464b3e70012f71edc0 with changes in files: ** ** */ #ifndef SQLITE_AMALGAMATION #define SQLITE_CORE 1 #define SQLITE_AMALGAMATION 1 #ifndef SQLITE_PRIVATE |
| ︙ | ︙ | |||
463 464 465 466 467 468 469 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.50.0" #define SQLITE_VERSION_NUMBER 3050000 | | | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.50.0" #define SQLITE_VERSION_NUMBER 3050000 #define SQLITE_SOURCE_ID "2025-03-16 00:13:29 18bda13e197e4b4ec7464b3e70012f71edc05f73d8b14bb48bad452f81c7e185" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database | > > > > > > | 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 | ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** ** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]] ** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the ** VFS to block when taking a SHARED lock to connect to a wal mode database. ** This is used to implement the functionality associated with ** SQLITE_SETLK_BLOCK_ON_CONNECT. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database |
| ︙ | ︙ | |||
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO | > | 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 | #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 #define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO |
| ︙ | ︙ | |||
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 | ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 | ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Set the Setlk Timeout ** METHOD: sqlite3 ** ** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If ** the VFS supports blocking locks, it sets the timeout in ms used by ** eligible locks taken on wal mode databases by the specified database ** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does ** not support blocking locks, this function is a no-op. ** ** Passing 0 to this function disables blocking locks altogether. Passing ** -1 to this function requests that the VFS blocks for a long time - ** indefinitely if possible. The results of passing any other negative value ** are undefined. ** ** Internally, each SQLite database handle store two timeout values - the ** busy-timeout (used for rollback mode databases, or if the VFS does not ** support blocking locks) and the setlk-timeout (used for blocking locks ** on wal-mode databases). The sqlite3_busy_timeout() method sets both ** values, this function sets only the setlk-timeout value. Therefore, ** to configure separate busy-timeout and setlk-timeout values for a single ** database handle, call sqlite3_busy_timeout() followed by this function. ** ** Whenever the number of connections to a wal mode database falls from ** 1 to 0, the last connection takes an exclusive lock on the database, ** then checkpoints and deletes the wal file. While it is doing this, any ** new connection that tries to read from the database fails with an ** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is ** passed to this API, the new connection blocks until the exclusive lock ** has been released. */ SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); /* ** CAPI3REF: Flags for sqlite3_setlk_timeout() */ #define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** |
| ︙ | ︙ | |||
5445 5446 5447 5448 5449 5450 5451 | ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from | | | 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 | ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error ** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option ** can be used to restore the legacy behavior. ** |
| ︙ | ︙ | |||
7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 | ** to be invoked whenever a row is updated, inserted or deleted in ** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. | > > | 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 | ** to be invoked whenever a row is updated, inserted or deleted in ** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The update hook is disabled by invoking sqlite3_update_hook() ** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. |
| ︙ | ︙ | |||
14095 14096 14097 14098 14099 14100 14101 | ** * Columns in an index ** * Columns in a view ** * Terms in the SET clause of an UPDATE statement ** * Terms in the result set of a SELECT statement ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** | | > > > > > > | > > | 14142 14143 14144 14145 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 14163 14164 14165 14166 14167 14168 14169 14170 14171 | ** * Columns in an index ** * Columns in a view ** * Terms in the SET clause of an UPDATE statement ** * Terms in the result set of a SELECT statement ** * Terms in the GROUP BY or ORDER BY clauses of a SELECT statement. ** * Terms in the VALUES clause of an INSERT statement ** ** The hard upper limit here is 32767. Most database people will ** tell you that in a well-normalized database, you usually should ** not have more than a dozen or so columns in any table. And if ** that is the case, there is no point in having more than a few ** dozen values in any of the other situations described above. ** ** An index can only have SQLITE_MAX_COLUMN columns from the user ** point of view, but the underlying b-tree that implements the index ** might have up to twice as many columns in a WITHOUT ROWID table, ** since must also store the primary key at the end. Hence the ** column count for Index is u16 instead of i16. */ #if !defined(SQLITE_MAX_COLUMN) # define SQLITE_MAX_COLUMN 2000 #elif SQLITE_MAX_COLUMN>32767 # error SQLITE_MAX_COLUMN may not exceed 32767 #endif /* ** The maximum length of a single SQL statement in bytes. ** ** It used to be the case that setting this value to zero would ** turn the limit off. That is no longer true. It is not possible |
| ︙ | ︙ | |||
15115 15116 15117 15118 15119 15120 15121 | #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof | | > > > > > > > > > > | 15170 15171 15172 15173 15174 15175 15176 15177 15178 15179 15180 15181 15182 15183 15184 15185 15186 15187 15188 15189 15190 15191 15192 15193 15194 | #endif /* ** GCC does not define the offsetof() macro so we'll have to do it ** ourselves. */ #ifndef offsetof #define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) #endif /* ** Work around C99 "flex-array" syntax for pre-C99 compilers, so as ** to avoid complaints from -fsanitize=strict-bounds. */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define FLEXARRAY #else # define FLEXARRAY 1 #endif /* ** Macros to compute minimum and maximum of two numbers. */ #ifndef MIN # define MIN(A,B) ((A)<(B)?(A):(B)) |
| ︙ | ︙ | |||
17350 17351 17352 17353 17354 17355 17356 | SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val); SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif | | | | 17415 17416 17417 17418 17419 17420 17421 17422 17423 17424 17425 17426 17427 17428 17429 17430 | SQLITE_PRIVATE void sqlite3MemSetArrayInt64(sqlite3_value *aMem, int iIdx, i64 val); SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*); #ifdef SQLITE_ENABLE_BYTECODE_VTAB SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*); #endif /* Use SQLITE_ENABLE_EXPLAIN_COMMENTS to enable generation of extra ** comments on each VDBE opcode. ** ** Use the SQLITE_ENABLE_MODULE_COMMENTS macro to see some extra no-op ** comments in VDBE programs that show key decision points in the code ** generator. */ #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS SQLITE_PRIVATE void sqlite3VdbeComment(Vdbe*, const char*, ...); |
| ︙ | ︙ | |||
18074 18075 18076 18077 18078 18079 18080 18081 18082 18083 18084 18085 18086 18087 | Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ DbClientData *pDbData; /* sqlite3_set_clientdata() content */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY | > > > > | 18139 18140 18141 18142 18143 18144 18145 18146 18147 18148 18149 18150 18151 18152 18153 18154 18155 18156 | Hash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ BusyHandler busyHandler; /* Busy callback */ Db aDbStatic[2]; /* Static space for the 2 default backends */ Savepoint *pSavepoint; /* List of active savepoints */ int nAnalysisLimit; /* Number of index rows to ANALYZE */ int busyTimeout; /* Busy handler timeout, in msec */ #ifdef SQLITE_ENABLE_SETLK_TIMEOUT int setlkTimeout; /* Blocking lock timeout, in msec. -1 -> inf. */ int setlkFlags; /* Flags passed to setlk_timeout() */ #endif int nSavepoint; /* Number of non-transaction savepoints */ int nStatement; /* Number of nested statement-transactions */ i64 nDeferredCons; /* Net deferred constraints this transaction. */ i64 nDeferredImmCons; /* Net deferred immediate constraints */ int *pnBytesFreed; /* If not NULL, increment this in DbFree() */ DbClientData *pDbData; /* sqlite3_set_clientdata() content */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY |
| ︙ | ︙ | |||
18886 18887 18888 18889 18890 18891 18892 |
/* EV: R-30323-21917 */
u8 isDeferred; /* True if constraint checking is deferred till COMMIT */
u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */
Trigger *apTrigger[2];/* Triggers for aAction[] actions */
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
int iFrom; /* Index of column in pFrom */
char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */
| | > > > > | 18955 18956 18957 18958 18959 18960 18961 18962 18963 18964 18965 18966 18967 18968 18969 18970 18971 18972 18973 18974 |
/* EV: R-30323-21917 */
u8 isDeferred; /* True if constraint checking is deferred till COMMIT */
u8 aAction[2]; /* ON DELETE and ON UPDATE actions, respectively */
Trigger *apTrigger[2];/* Triggers for aAction[] actions */
struct sColMap { /* Mapping of columns in pFrom to columns in zTo */
int iFrom; /* Index of column in pFrom */
char *zCol; /* Name of column in zTo. If NULL use PRIMARY KEY */
} aCol[FLEXARRAY]; /* One entry for each of nCol columns */
};
/* The size (in bytes) of an FKey object holding N columns. The answer
** does NOT include space to hold the zTo name. */
#define SZ_FKEY(N) (offsetof(FKey,aCol)+(N)*sizeof(struct sColMap))
/*
** SQLite supports many different ways to resolve a constraint
** error. ROLLBACK processing means that a constraint violation
** causes the operation in process to fail and for the current transaction
** to be rolled back. ABORT processing means the operation in process
** fails and any prior changes from that one operation are backed out,
|
| ︙ | ︙ | |||
18950 18951 18952 18953 18954 18955 18956 |
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
u16 nKeyField; /* Number of key columns in the index */
u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortFlags; /* Sort order for each column. */
| | > > > | 19023 19024 19025 19026 19027 19028 19029 19030 19031 19032 19033 19034 19035 19036 19037 19038 19039 19040 19041 19042 |
struct KeyInfo {
u32 nRef; /* Number of references to this KeyInfo object */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
u16 nKeyField; /* Number of key columns in the index */
u16 nAllField; /* Total columns, including key plus others */
sqlite3 *db; /* The database connection */
u8 *aSortFlags; /* Sort order for each column. */
CollSeq *aColl[FLEXARRAY]; /* Collating sequence for each term of the key */
};
/* The size (in bytes) of a KeyInfo object with up to N fields */
#define SZ_KEYINFO(N) (offsetof(KeyInfo,aColl) + (N)*sizeof(CollSeq*))
/*
** Allowed bit values for entries in the KeyInfo.aSortFlags[] array.
*/
#define KEYINFO_ORDER_DESC 0x01 /* DESC sort order */
#define KEYINFO_ORDER_BIGNULL 0x02 /* NULL is larger than any other value */
/*
|
| ︙ | ︙ | |||
19072 19073 19074 19075 19076 19077 19078 | u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ const char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ | | | 19148 19149 19150 19151 19152 19153 19154 19155 19156 19157 19158 19159 19160 19161 19162 | u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ const char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ ExprList *aColExpr; /* Column expressions */ Pgno tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ u16 nColumn; /* Nr columns in btree. Can be 2*Table.nCol */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ unsigned idxType:2; /* 0:Normal 1:UNIQUE, 2:PRIMARY KEY, 3:IPK */ unsigned bUnordered:1; /* Use this index for == or IN queries only */ unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */ unsigned isResized:1; /* True if resizeIndexObject() has been called */ unsigned isCovering:1; /* True if this is a covering index */ unsigned noSkipScan:1; /* Do not try to use skip-scan if true */ |
| ︙ | ︙ | |||
19410 19411 19412 19413 19414 19415 19416 | ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ | | | | | | 19486 19487 19488 19489 19490 19491 19492 19493 19494 19495 19496 19497 19498 19499 19500 19501 19502 19503 | ** upwards into parent nodes. */ #define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc) /* Macros can be used to test, set, or clear bits in the ** Expr.flags field. */ #define ExprHasProperty(E,P) (((E)->flags&(u32)(P))!=0) #define ExprHasAllProperty(E,P) (((E)->flags&(u32)(P))==(u32)(P)) #define ExprSetProperty(E,P) (E)->flags|=(u32)(P) #define ExprClearProperty(E,P) (E)->flags&=~(u32)(P) #define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse) #define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0) /* Macros used to ensure that the correct members of unions are accessed ** in Expr. */ |
| ︙ | ︙ | |||
19525 19526 19527 19528 19529 19530 19531 |
struct { /* Used by any ExprList other than Parse.pConsExpr */
u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
} x;
int iConstExprReg; /* Register in which Expr value is cached. Used only
** by Parse.pConstExpr */
} u;
| | > > > > > | 19601 19602 19603 19604 19605 19606 19607 19608 19609 19610 19611 19612 19613 19614 19615 19616 19617 19618 19619 19620 19621 |
struct { /* Used by any ExprList other than Parse.pConsExpr */
u16 iOrderByCol; /* For ORDER BY, column number in result set */
u16 iAlias; /* Index into Parse.aAlias[] for zName */
} x;
int iConstExprReg; /* Register in which Expr value is cached. Used only
** by Parse.pConstExpr */
} u;
} a[FLEXARRAY]; /* One slot for each expression in the list */
};
/* The size (in bytes) of an ExprList object that is big enough to hold
** as many as N expressions. */
#define SZ_EXPRLIST(N) \
(offsetof(ExprList,a) + (N)*sizeof(struct ExprList_item))
/*
** Allowed values for Expr.a.eEName
*/
#define ENAME_NAME 0 /* The AS clause of a result set */
#define ENAME_SPAN 1 /* Complete text of the result set expression */
#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
|
| ︙ | ︙ | |||
19555 19556 19557 19558 19559 19560 19561 |
**
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
*/
struct IdList {
int nId; /* Number of identifiers on the list */
struct IdList_item {
char *zName; /* Name of the identifier */
| | > > > | 19636 19637 19638 19639 19640 19641 19642 19643 19644 19645 19646 19647 19648 19649 19650 19651 19652 19653 19654 19655 |
**
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
*/
struct IdList {
int nId; /* Number of identifiers on the list */
struct IdList_item {
char *zName; /* Name of the identifier */
} a[FLEXARRAY];
};
/* The size (in bytes) of an IdList object that can hold up to N IDs. */
#define SZ_IDLIST(N) (offsetof(IdList,a)+(N)*sizeof(struct IdList_item))
/*
** Allowed values for IdList.eType, which determines which value of the a.u4
** is valid.
*/
#define EU4_NONE 0 /* Does not use IdList.a.u4 */
#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
|
| ︙ | ︙ | |||
19677 19678 19679 19680 19681 19682 19683 |
** This object represents one or more tables that are the source of
** content for an SQL statement. For example, a single SrcList object
** is used to hold the FROM clause of a SELECT statement. SrcList also
** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
*/
struct SrcList {
| | | | > > > > > > > > | 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771 19772 19773 19774 19775 19776 19777 19778 19779 19780 19781 19782 19783 19784 19785 19786 |
** This object represents one or more tables that are the source of
** content for an SQL statement. For example, a single SrcList object
** is used to hold the FROM clause of a SELECT statement. SrcList also
** represents the target tables for DELETE, INSERT, and UPDATE statements.
**
*/
struct SrcList {
int nSrc; /* Number of tables or subqueries in the FROM clause */
u32 nAlloc; /* Number of entries allocated in a[] below */
SrcItem a[FLEXARRAY]; /* One entry for each identifier on the list */
};
/* Size (in bytes) of a SrcList object that can hold as many as N
** SrcItem objects. */
#define SZ_SRCLIST(N) (offsetof(SrcList,a)+(N)*sizeof(SrcItem))
/* Size (in bytes( of a SrcList object that holds 1 SrcItem. This is a
** special case of SZ_SRCITEM(1) that comes up often. */
#define SZ_SRCLIST_1 (offsetof(SrcList,a)+sizeof(SrcItem))
/*
** Permitted values of the SrcList.a.jointype field
*/
#define JT_INNER 0x01 /* Any kind of inner or cross join */
#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */
#define JT_NATURAL 0x04 /* True for a "natural" join */
|
| ︙ | ︙ | |||
20745 20746 20747 20748 20749 20750 20751 |
** An instance of the With object represents a WITH clause containing
** one or more CTEs (common table expressions).
*/
struct With {
int nCte; /* Number of CTEs in the WITH clause */
int bView; /* Belongs to the outermost Select of a view */
With *pOuter; /* Containing WITH clause, or NULL */
| | > > > > | 20837 20838 20839 20840 20841 20842 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 |
** An instance of the With object represents a WITH clause containing
** one or more CTEs (common table expressions).
*/
struct With {
int nCte; /* Number of CTEs in the WITH clause */
int bView; /* Belongs to the outermost Select of a view */
With *pOuter; /* Containing WITH clause, or NULL */
Cte a[FLEXARRAY]; /* For each CTE in the WITH clause.... */
};
/* The size (in bytes) of a With object that can hold as many
** as N different CTEs. */
#define SZ_WITH(N) (offsetof(With,a) + (N)*sizeof(Cte))
/*
** The Cte object is not guaranteed to persist for the entire duration
** of code generation. (The query flattener or other parser tree
** edits might delete it.) The following object records information
** about each Common Table Expression that must be preserved for the
** duration of the parse.
|
| ︙ | ︙ | |||
20776 20777 20778 20779 20780 20781 20782 |
/* Client data associated with sqlite3_set_clientdata() and
** sqlite3_get_clientdata().
*/
struct DbClientData {
DbClientData *pNext; /* Next in a linked list */
void *pData; /* The data */
void (*xDestructor)(void*); /* Destructor. Might be NULL */
| | > > > > | 20872 20873 20874 20875 20876 20877 20878 20879 20880 20881 20882 20883 20884 20885 20886 20887 20888 20889 20890 20891 |
/* Client data associated with sqlite3_set_clientdata() and
** sqlite3_get_clientdata().
*/
struct DbClientData {
DbClientData *pNext; /* Next in a linked list */
void *pData; /* The data */
void (*xDestructor)(void*); /* Destructor. Might be NULL */
char zName[FLEXARRAY]; /* Name of this client data. MUST BE LAST */
};
/* The size (in bytes) of a DbClientData object that can has a name
** that is N bytes long, including the zero-terminator. */
#define SZ_DBCLIENTDATA(N) (offsetof(DbClientData,zName)+(N))
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
** data structures on sqlite3DebugPrintf() using a tree-like view.
*/
struct TreeView {
|
| ︙ | ︙ | |||
21221 21222 21223 21224 21225 21226 21227 | SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); | | | 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333 21334 21335 | SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*); SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect); SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char); SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char); SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int); SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*); SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index*, int); #ifdef SQLITE_OMIT_GENERATED_COLUMNS # define sqlite3TableColumnToStorage(T,X) (X) /* No-op pass-through */ # define sqlite3StorageColumnToTable(T,X) (X) /* No-op pass-through */ #else SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table*, i16); SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table*, i16); #endif |
| ︙ | ︙ | |||
21319 21320 21321 21322 21323 21324 21325 | SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *); SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*); SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*); SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*); SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*); SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*); | | | 21419 21420 21421 21422 21423 21424 21425 21426 21427 21428 21429 21430 21431 21432 21433 |
SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *);
SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*);
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,int,int,char**);
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
Expr*, int, int, u8);
SQLITE_PRIVATE void sqlite3DropIndex(Parse*, SrcList*, int);
SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
|
| ︙ | ︙ | |||
21455 21456 21457 21458 21459 21460 21461 | SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); | | > | 21555 21556 21557 21558 21559 21560 21561 21562 21563 21564 21565 21566 21567 21568 21569 21570 | SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int); SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int); SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*); SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int); SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*); SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int); SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*,int); SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char*, u32); SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void); SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void); SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void); SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*); #if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*); #endif |
| ︙ | ︙ | |||
22555 22556 22557 22558 22559 22560 22561 22562 22563 22564 22565 22566 22567 22568 | "ENABLE_RBU", #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif #ifdef SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif | > > > | 22656 22657 22658 22659 22660 22661 22662 22663 22664 22665 22666 22667 22668 22669 22670 22671 22672 | "ENABLE_RBU", #endif #ifdef SQLITE_ENABLE_RTREE "ENABLE_RTREE", #endif #ifdef SQLITE_ENABLE_SESSION "ENABLE_SESSION", #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT "ENABLE_SETLK_TIMEOUT", #endif #ifdef SQLITE_ENABLE_SNAPSHOT "ENABLE_SNAPSHOT", #endif #ifdef SQLITE_ENABLE_SORTER_REFERENCES "ENABLE_SORTER_REFERENCES", #endif |
| ︙ | ︙ | |||
22610 22611 22612 22613 22614 22615 22616 22617 22618 22619 22620 22621 22622 22623 | #endif #ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), #endif #ifdef SQLITE_FTS5_ENABLE_TEST_MI | > > > | 22714 22715 22716 22717 22718 22719 22720 22721 22722 22723 22724 22725 22726 22727 22728 22729 22730 | #endif #ifdef SQLITE_EXTRA_IFNULLROW "EXTRA_IFNULLROW", #endif #ifdef SQLITE_EXTRA_INIT "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT), #endif #ifdef SQLITE_EXTRA_INIT_MUTEXED "EXTRA_INIT_MUTEXED=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT_MUTEXED), #endif #ifdef SQLITE_EXTRA_SHUTDOWN "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN), #endif #ifdef SQLITE_FTS3_MAX_EXPR_DEPTH "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH), #endif #ifdef SQLITE_FTS5_ENABLE_TEST_MI |
| ︙ | ︙ | |||
23594 23595 23596 23597 23598 23599 23600 | u32 payloadSize; /* Total number of bytes in the record */ u32 szRow; /* Byte available in aRow */ #ifdef SQLITE_ENABLE_COLUMN_USED_MASK u64 maskUsed; /* Mask of columns used by this cursor */ #endif VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */ | | < | | > > > > > > > > | 23701 23702 23703 23704 23705 23706 23707 23708 23709 23710 23711 23712 23713 23714 23715 23716 23717 23718 23719 23720 23721 23722 23723 23724 23725 23726 23727 |
u32 payloadSize; /* Total number of bytes in the record */
u32 szRow; /* Byte available in aRow */
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */
#endif
VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
/* Space is allocated for aType to hold at least 2*nField+1 entries:
** nField slots for aType[] and nField+1 array slots for aOffset[] */
u32 aType[FLEXARRAY]; /* Type values record decode. MUST BE LAST */
};
/*
** The size (in bytes) of a VdbeCursor object that has an nField value of N
** or less. The value of SZ_VDBECURSOR(n) is guaranteed to be a multiple
** of 8.
*/
#define SZ_VDBECURSOR(N) \
(ROUND8(offsetof(VdbeCursor,aType)) + ((N)+1)*sizeof(u64))
/* Return true if P is a null-only cursor
*/
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
|
| ︙ | ︙ | |||
23856 23857 23858 23859 23860 23861 23862 | Mem *pMem; /* Memory cell used to store aggregate context */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u16 argc; /* Number of arguments */ | | > > > > > > > | 23970 23971 23972 23973 23974 23975 23976 23977 23978 23979 23980 23981 23982 23983 23984 23985 23986 23987 23988 23989 23990 23991 23992 23993 | Mem *pMem; /* Memory cell used to store aggregate context */ Vdbe *pVdbe; /* The VM that owns this context */ int iOp; /* Instruction number of OP_Function */ int isError; /* Error code returned by the function. */ u8 enc; /* Encoding to use for results */ u8 skipFlag; /* Skip accumulator loading if true */ u16 argc; /* Number of arguments */ sqlite3_value *argv[FLEXARRAY]; /* Argument set */ }; /* ** The size (in bytes) of an sqlite3_context object that holds N ** argv[] arguments. */ #define SZ_CONTEXT(N) \ (offsetof(sqlite3_context,argv)+(N)*sizeof(sqlite3_value*)) /* The ScanStatus object holds a single value for the ** sqlite3_stmt_scanstatus() interface. ** ** aAddrRange[]: ** This array is used by ScanStatus elements associated with EQP ** notes that make an SQLITE_SCANSTAT_NCYCLE value available. It is |
| ︙ | ︙ | |||
23992 23993 23994 23995 23996 23997 23998 |
** sqlite3_preupdate_*() API functions.
*/
struct PreUpdate {
Vdbe *v;
VdbeCursor *pCsr; /* Cursor to read old values from */
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
u8 *aRecord; /* old.* database record */
| | > | 24113 24114 24115 24116 24117 24118 24119 24120 24121 24122 24123 24124 24125 24126 24127 24128 24129 24130 24131 24132 24133 24134 24135 24136 24137 24138 24139 |
** sqlite3_preupdate_*() API functions.
*/
struct PreUpdate {
Vdbe *v;
VdbeCursor *pCsr; /* Cursor to read old values from */
int op; /* One of SQLITE_INSERT, UPDATE, DELETE */
u8 *aRecord; /* old.* database record */
KeyInfo *pKeyinfo; /* Key information */
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
int iNewReg; /* Register for new.* values */
int iBlobWrite; /* Value returned by preupdate_blobwrite() */
i64 iKey1; /* First key value passed to hook */
i64 iKey2; /* Second key value passed to hook */
Mem oldipk; /* Memory cell holding "old" IPK value */
Mem *aNew; /* Array of new.* values */
Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
sqlite3_value **apDflt; /* Array of default values, if required */
u8 keyinfoSpace[SZ_KEYINFO(0)]; /* Space to hold pKeyinfo[0] content */
};
/*
** An instance of this object is used to pass an vector of values into
** OP_VFilter, the xFilter method of a virtual table. The vector is the
** set of values on the right-hand side of an IN constraint.
**
|
| ︙ | ︙ | |||
24370 24371 24372 24373 24374 24375 24376 |
SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
u32 nInit = countLookasideSlots(db->lookaside.pInit);
u32 nFree = countLookasideSlots(db->lookaside.pFree);
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
nInit += countLookasideSlots(db->lookaside.pSmallInit);
nFree += countLookasideSlots(db->lookaside.pSmallFree);
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
| > | | | 24492 24493 24494 24495 24496 24497 24498 24499 24500 24501 24502 24503 24504 24505 24506 24507 24508 |
SQLITE_PRIVATE int sqlite3LookasideUsed(sqlite3 *db, int *pHighwater){
u32 nInit = countLookasideSlots(db->lookaside.pInit);
u32 nFree = countLookasideSlots(db->lookaside.pFree);
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
nInit += countLookasideSlots(db->lookaside.pSmallInit);
nFree += countLookasideSlots(db->lookaside.pSmallFree);
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
assert( db->lookaside.nSlot >= nInit+nFree );
if( pHighwater ) *pHighwater = (int)(db->lookaside.nSlot - nInit);
return (int)(db->lookaside.nSlot - (nInit+nFree));
}
/*
** Query status information for a single database connection
*/
SQLITE_API int sqlite3_db_status(
sqlite3 *db, /* The database connection whose status is desired */
|
| ︙ | ︙ | |||
24424 24425 24426 24427 24428 24429 24430 |
case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
*pCurrent = 0;
| | | 24547 24548 24549 24550 24551 24552 24553 24554 24555 24556 24557 24558 24559 24560 24561 |
case SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL: {
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_HIT );
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE );
testcase( op==SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL );
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)>=0 );
assert( (op-SQLITE_DBSTATUS_LOOKASIDE_HIT)<3 );
*pCurrent = 0;
*pHighwater = (int)db->lookaside.anStat[op-SQLITE_DBSTATUS_LOOKASIDE_HIT];
if( resetFlag ){
db->lookaside.anStat[op - SQLITE_DBSTATUS_LOOKASIDE_HIT] = 0;
}
break;
}
/*
|
| ︙ | ︙ | |||
25936 25937 25938 25939 25940 25941 25942 | /* ** Return the number of days after the most recent Sunday. ** ** In other words, return the day of the week according ** to this code: ** | | | 26059 26060 26061 26062 26063 26064 26065 26066 26067 26068 26069 26070 26071 26072 26073 |
/*
** Return the number of days after the most recent Sunday.
**
** In other words, return the day of the week according
** to this code:
**
** 0=Sunday, 1=Monday, 2=Tuesday, ..., 6=Saturday
*/
static int daysAfterSunday(DateTime *pDate){
assert( pDate->validJD );
return (int)((pDate->iJD+129600000)/86400000) % 7;
}
/*
|
| ︙ | ︙ | |||
31539 31540 31541 31542 31543 31544 31545 | #define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */ #define etSIZE 4 /* Return number of characters processed so far. %n */ #define etSTRING 5 /* Strings. %s */ #define etDYNSTRING 6 /* Dynamically allocated strings. %z */ #define etPERCENT 7 /* Percent symbol. %% */ #define etCHARX 8 /* Characters. %c */ /* The rest are extensions, not normally found in printf() */ | | | | | | | | | | | | 31662 31663 31664 31665 31666 31667 31668 31669 31670 31671 31672 31673 31674 31675 31676 31677 31678 31679 31680 31681 31682 31683 31684 31685 31686 |
#define etGENERIC 3 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 4 /* Return number of characters processed so far. %n */
#define etSTRING 5 /* Strings. %s */
#define etDYNSTRING 6 /* Dynamically allocated strings. %z */
#define etPERCENT 7 /* Percent symbol. %% */
#define etCHARX 8 /* Characters. %c */
/* The rest are extensions, not normally found in printf() */
#define etESCAPE_q 9 /* Strings with '\'' doubled. %q */
#define etESCAPE_Q 10 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
#define etTOKEN 11 /* a pointer to a Token structure */
#define etSRCITEM 12 /* a pointer to a SrcItem */
#define etPOINTER 13 /* The %p conversion */
#define etESCAPE_w 14 /* %w -> Strings with '\"' doubled */
#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
#define etDECIMAL 16 /* %d or %u, but not %x, %o */
#define etINVALID 17 /* Any unrecognized conversion type */
/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;
|
| ︙ | ︙ | |||
31588 31589 31590 31591 31592 31593 31594 |
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etDECIMAL, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
| | | | | 31711 31712 31713 31714 31715 31716 31717 31718 31719 31720 31721 31722 31723 31724 31725 31726 31727 |
static const char aDigits[] = "0123456789ABCDEF0123456789abcdef";
static const char aPrefix[] = "-x0\000X0";
static const et_info fmtinfo[] = {
{ 'd', 10, 1, etDECIMAL, 0, 0 },
{ 's', 0, 4, etSTRING, 0, 0 },
{ 'g', 0, 1, etGENERIC, 30, 0 },
{ 'z', 0, 4, etDYNSTRING, 0, 0 },
{ 'q', 0, 4, etESCAPE_q, 0, 0 },
{ 'Q', 0, 4, etESCAPE_Q, 0, 0 },
{ 'w', 0, 4, etESCAPE_w, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, 0, 2 },
{ 'u', 10, 0, etDECIMAL, 0, 0 },
{ 'x', 16, 0, etRADIX, 16, 1 },
{ 'X', 16, 0, etRADIX, 0, 4 },
#ifndef SQLITE_OMIT_FLOATING_POINT
{ 'f', 0, 1, etFLOAT, 0, 0 },
|
| ︙ | ︙ | |||
32187 32188 32189 32190 32191 32192 32193 |
}
}
}else{
buf[0] = 0;
}
}else{
unsigned int ch = va_arg(ap,unsigned int);
| < < | < < < < < < < < < < < < < < < < | 32310 32311 32312 32313 32314 32315 32316 32317 32318 32319 32320 32321 32322 32323 32324 |
}
}
}else{
buf[0] = 0;
}
}else{
unsigned int ch = va_arg(ap,unsigned int);
length = sqlite3AppendOneUtf8Character(buf, ch);
}
if( precision>1 ){
i64 nPrior = 1;
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlite3_str_appendchar(pAccum, width-1, ' ');
width = 0;
|
| ︙ | ︙ | |||
32285 32286 32287 32288 32289 32290 32291 |
adjust_width_for_utf8:
if( flag_altform2 && width>0 ){
/* Adjust width to account for extra bytes in UTF-8 characters */
int ii = length - 1;
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
}
break;
| | | | | < > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > | > > > > > > > > | | > > > > > > > > > > > > > > > > | | > | > > > | 32390 32391 32392 32393 32394 32395 32396 32397 32398 32399 32400 32401 32402 32403 32404 32405 32406 32407 32408 32409 32410 32411 32412 32413 32414 32415 32416 32417 32418 32419 32420 32421 32422 32423 32424 32425 32426 32427 32428 32429 32430 32431 32432 32433 32434 32435 32436 32437 32438 32439 32440 32441 32442 32443 32444 32445 32446 32447 32448 32449 32450 32451 32452 32453 32454 32455 32456 32457 32458 32459 32460 32461 32462 32463 32464 32465 32466 32467 32468 32469 32470 32471 32472 32473 32474 32475 32476 32477 32478 32479 32480 32481 32482 32483 32484 32485 32486 32487 32488 32489 32490 32491 32492 32493 32494 32495 32496 32497 32498 32499 32500 32501 32502 32503 32504 32505 32506 32507 |
adjust_width_for_utf8:
if( flag_altform2 && width>0 ){
/* Adjust width to account for extra bytes in UTF-8 characters */
int ii = length - 1;
while( ii>=0 ) if( (bufpt[ii--] & 0xc0)==0x80 ) width++;
}
break;
case etESCAPE_q: /* %q: Escape ' characters */
case etESCAPE_Q: /* %Q: Escape ' and enclose in '...' */
case etESCAPE_w: { /* %w: Escape " characters */
i64 i, j, k, n;
int needQuote = 0;
char ch;
char *escarg;
char q;
if( bArgList ){
escarg = getTextArg(pArgList);
}else{
escarg = va_arg(ap,char*);
}
if( escarg==0 ){
escarg = (xtype==etESCAPE_Q ? "NULL" : "(NULL)");
}else if( xtype==etESCAPE_Q ){
needQuote = 1;
}
if( xtype==etESCAPE_w ){
q = '"';
flag_alternateform = 0;
}else{
q = '\'';
}
/* For %q, %Q, and %w, the precision is the number of bytes (or
** characters if the ! flags is present) to use from the input.
** Because of the extra quoting characters inserted, the number
** of output characters may be larger than the precision.
*/
k = precision;
for(i=n=0; k!=0 && (ch=escarg[i])!=0; i++, k--){
if( ch==q ) n++;
if( flag_altform2 && (ch&0xc0)==0xc0 ){
while( (escarg[i+1]&0xc0)==0x80 ){ i++; }
}
}
if( flag_alternateform ){
/* For %#q, do unistr()-style backslash escapes for
** all control characters, and for backslash itself.
** For %#Q, do the same but only if there is at least
** one control character. */
u32 nBack = 0;
u32 nCtrl = 0;
for(k=0; k<i; k++){
if( escarg[k]=='\\' ){
nBack++;
}else if( ((u8*)escarg)[k]<=0x1f ){
nCtrl++;
}
}
if( nCtrl || xtype==etESCAPE_q ){
n += nBack + 5*nCtrl;
if( xtype==etESCAPE_Q ){
n += 10;
needQuote = 2;
}
}else{
flag_alternateform = 0;
}
}
n += i + 3;
if( n>etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, n);
if( bufpt==0 ) return;
}else{
bufpt = buf;
}
j = 0;
if( needQuote ){
if( needQuote==2 ){
memcpy(&bufpt[j], "unistr('", 8);
j += 8;
}else{
bufpt[j++] = '\'';
}
}
k = i;
if( flag_alternateform ){
for(i=0; i<k; i++){
bufpt[j++] = ch = escarg[i];
if( ch==q ){
bufpt[j++] = ch;
}else if( ch=='\\' ){
bufpt[j++] = '\\';
}else if( ((unsigned char)ch)<=0x1f ){
bufpt[j-1] = '\\';
bufpt[j++] = 'u';
bufpt[j++] = '0';
bufpt[j++] = '0';
bufpt[j++] = ch>=0x10 ? '1' : '0';
bufpt[j++] = "0123456789abcdef"[ch&0xf];
}
}
}else{
for(i=0; i<k; i++){
bufpt[j++] = ch = escarg[i];
if( ch==q ) bufpt[j++] = ch;
}
}
if( needQuote ){
bufpt[j++] = '\'';
if( needQuote==2 ) bufpt[j++] = ')';
}
bufpt[j] = 0;
length = j;
goto adjust_width_for_utf8;
}
case etTOKEN: {
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
if( flag_alternateform ){
|
| ︙ | ︙ | |||
34826 34827 34828 34829 34830 34831 34832 34833 34834 34835 34836 34837 34838 34839 |
}else{ \
*zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
*zOut++ = (u8)(c&0x00FF); \
} \
}
/*
** Translate a single UTF-8 character. Return the unicode value.
**
** During translation, assume that the byte that zTerm points
** is a 0x00.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 34991 34992 34993 34994 34995 34996 34997 34998 34999 35000 35001 35002 35003 35004 35005 35006 35007 35008 35009 35010 35011 35012 35013 35014 35015 35016 35017 35018 35019 35020 35021 35022 35023 35024 35025 35026 35027 35028 35029 35030 35031 35032 35033 |
}else{ \
*zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03)); \
*zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0)); \
*zOut++ = (u8)(0x00DC + ((c>>8)&0x03)); \
*zOut++ = (u8)(c&0x00FF); \
} \
}
/*
** Write a single UTF8 character whose value is v into the
** buffer starting at zOut. zOut must be sized to hold at
** least for bytes. Return the number of bytes needed
** to encode the new character.
*/
SQLITE_PRIVATE int sqlite3AppendOneUtf8Character(char *zOut, u32 v){
if( v<0x00080 ){
zOut[0] = (u8)(v & 0xff);
return 1;
}
if( v<0x00800 ){
zOut[0] = 0xc0 + (u8)((v>>6) & 0x1f);
zOut[1] = 0x80 + (u8)(v & 0x3f);
return 2;
}
if( v<0x10000 ){
zOut[0] = 0xe0 + (u8)((v>>12) & 0x0f);
zOut[1] = 0x80 + (u8)((v>>6) & 0x3f);
zOut[2] = 0x80 + (u8)(v & 0x3f);
return 3;
}
zOut[0] = 0xf0 + (u8)((v>>18) & 0x07);
zOut[1] = 0x80 + (u8)((v>>12) & 0x3f);
zOut[2] = 0x80 + (u8)((v>>6) & 0x3f);
zOut[3] = 0x80 + (u8)(v & 0x3f);
return 4;
}
/*
** Translate a single UTF-8 character. Return the unicode value.
**
** During translation, assume that the byte that zTerm points
** is a 0x00.
**
|
| ︙ | ︙ | |||
36932 36933 36934 36935 36936 36937 36938 | } *pA = iA*iB; return 0; #endif } /* | | | 37126 37127 37128 37129 37130 37131 37132 37133 37134 37135 37136 37137 37138 37139 37140 |
}
*pA = iA*iB;
return 0;
#endif
}
/*
** Compute the absolute value of a 32-bit signed integer, if possible. Or
** if the integer has a value of -2147483648, return +2147483647
*/
SQLITE_PRIVATE int sqlite3AbsInt32(int x){
if( x>=0 ) return x;
if( x==(int)0x80000000 ) return 0x7fffffff;
return -x;
}
|
| ︙ | ︙ | |||
38909 38910 38911 38912 38913 38914 38915 38916 38917 38918 38919 38920 38921 38922 | int openFlags; /* The flags specified at open() */ #endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ #endif #ifdef SQLITE_DEBUG /* The next group of variables are used to track whether or not the ** transaction counter in bytes 24-27 of database files are updated | > | 39103 39104 39105 39106 39107 39108 39109 39110 39111 39112 39113 39114 39115 39116 39117 | int openFlags; /* The flags specified at open() */ #endif #if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__) unsigned fsFlags; /* cached details from statfs() */ #endif #ifdef SQLITE_ENABLE_SETLK_TIMEOUT unsigned iBusyTimeout; /* Wait this many millisec on locks */ int bBlockOnConnect; /* True to block for SHARED locks */ #endif #if OS_VXWORKS struct vxworksFileId *pId; /* Unique file ID */ #endif #ifdef SQLITE_DEBUG /* The next group of variables are used to track whether or not the ** transaction counter in bytes 24-27 of database files are updated |
| ︙ | ︙ | |||
40302 40303 40304 40305 40306 40307 40308 40309 40310 40311 40312 40313 40314 40315 |
if( rc<0 ) return rc;
pInode->bProcessLock = 1;
pInode->nLock++;
}else{
rc = 0;
}
}else{
rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
}
return rc;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
| > > > > > > > | 40497 40498 40499 40500 40501 40502 40503 40504 40505 40506 40507 40508 40509 40510 40511 40512 40513 40514 40515 40516 40517 |
if( rc<0 ) return rc;
pInode->bProcessLock = 1;
pInode->nLock++;
}else{
rc = 0;
}
}else{
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( pFile->bBlockOnConnect && pLock->l_type==F_RDLCK
&& pLock->l_start==SHARED_FIRST && pLock->l_len==SHARED_SIZE
){
rc = osFcntl(pFile->h, F_SETLKW, pLock);
}else
#endif
rc = osSetPosixAdvisoryLock(pFile->h, pLock, pFile);
}
return rc;
}
/*
** Lock the file with the lock specified by parameter eFileLock - one
|
| ︙ | ︙ | |||
42663 42664 42665 42666 42667 42668 42669 42670 |
case SQLITE_FCNTL_HAS_MOVED: {
*(int*)pArg = fileHasMoved(pFile);
return SQLITE_OK;
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
| > | > > > > > | | 42865 42866 42867 42868 42869 42870 42871 42872 42873 42874 42875 42876 42877 42878 42879 42880 42881 42882 42883 42884 42885 42886 42887 42888 42889 42890 42891 42892 42893 42894 42895 |
case SQLITE_FCNTL_HAS_MOVED: {
*(int*)pArg = fileHasMoved(pFile);
return SQLITE_OK;
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
int iNew = *(int*)pArg;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = iNew<0 ? 0x7FFFFFFF : (unsigned)iNew;
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
pFile->iBusyTimeout = !!(*(int*)pArg);
#else
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
int iNew = *(int*)pArg;
pFile->bBlockOnConnect = iNew;
return SQLITE_OK;
}
#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
int rc = SQLITE_OK;
if( newLimit>sqlite3GlobalConfig.mxMmap ){
newLimit = sqlite3GlobalConfig.mxMmap;
}
|
| ︙ | ︙ | |||
43656 43657 43658 43659 43660 43661 43662 | ** ** In other words, if this is a blocking lock, none of the locks that ** occur later in the above list than the lock being obtained may be ** held. ** ** It is not permitted to block on the RECOVER lock. */ | | | 43864 43865 43866 43867 43868 43869 43870 43871 43872 43873 43874 43875 43876 43877 43878 |
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
** held.
**
** It is not permitted to block on the RECOVER lock.
*/
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
(ofst!=2) /* not RECOVER */
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
|
| ︙ | ︙ | |||
45465 45466 45467 45468 45469 45470 45471 | #if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0 struct timespec sp; sp.tv_sec = microseconds / 1000000; sp.tv_nsec = (microseconds % 1000000) * 1000; /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use | | | 45673 45674 45675 45676 45677 45678 45679 45680 45681 45682 45683 45684 45685 45686 45687 | #if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0 struct timespec sp; sp.tv_sec = microseconds / 1000000; sp.tv_nsec = (microseconds % 1000000) * 1000; /* Almost all modern unix systems support nanosleep(). But if you are ** compiling for one of the rare exceptions, you can use ** -DHAVE_NANOSLEEP=0 (perhaps in conjunction with -DHAVE_USLEEP if ** usleep() is available) in order to bypass the use of nanosleep() */ nanosleep(&sp, NULL); UNUSED_PARAMETER(NotUsed); return microseconds; #elif defined(HAVE_USLEEP) && HAVE_USLEEP if( microseconds>=1000000 ) sleep(microseconds/1000000); |
| ︙ | ︙ | |||
47186 47187 47188 47189 47190 47191 47192 47193 47194 47195 47196 47197 47198 47199 47200 |
#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch references */
HANDLE hMap; /* Handle for accessing memory mapping */
void *pMapRegion; /* Area memory mapped */
sqlite3_int64 mmapSize; /* Size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
};
/*
** The winVfsAppData structure is used for the pAppData member for all of the
** Win32 VFS variants.
*/
typedef struct winVfsAppData winVfsAppData;
struct winVfsAppData {
| > > > > > > > > > > | 47394 47395 47396 47397 47398 47399 47400 47401 47402 47403 47404 47405 47406 47407 47408 47409 47410 47411 47412 47413 47414 47415 47416 47417 47418 |
#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch references */
HANDLE hMap; /* Handle for accessing memory mapping */
void *pMapRegion; /* Area memory mapped */
sqlite3_int64 mmapSize; /* Size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
DWORD iBusyTimeout; /* Wait this many millisec on locks */
int bBlockOnConnect;
#endif
};
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
# define winFileBusyTimeout(pDbFd) pDbFd->iBusyTimeout
#else
# define winFileBusyTimeout(pDbFd) 0
#endif
/*
** The winVfsAppData structure is used for the pAppData member for all of the
** Win32 VFS variants.
*/
typedef struct winVfsAppData winVfsAppData;
struct winVfsAppData {
|
| ︙ | ︙ | |||
47621 47622 47623 47624 47625 47626 47627 47628 47629 47630 47631 47632 47633 47634 |
#else
{ "GetFullPathNameW", (SYSCALL)0, 0 },
#endif
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
LPWSTR*))aSyscall[25].pCurrent)
{ "GetLastError", (SYSCALL)GetLastError, 0 },
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
#if SQLITE_OS_WINCE
/* The GetProcAddressA() routine is only available on Windows CE. */
| > > > > > > | 47839 47840 47841 47842 47843 47844 47845 47846 47847 47848 47849 47850 47851 47852 47853 47854 47855 47856 47857 47858 |
#else
{ "GetFullPathNameW", (SYSCALL)0, 0 },
#endif
#define osGetFullPathNameW ((DWORD(WINAPI*)(LPCWSTR,DWORD,LPWSTR, \
LPWSTR*))aSyscall[25].pCurrent)
/*
** For GetLastError(), MSDN says:
**
** Minimum supported client: Windows XP [desktop apps | UWP apps]
** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
*/
{ "GetLastError", (SYSCALL)GetLastError, 0 },
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
#if SQLITE_OS_WINCE
/* The GetProcAddressA() routine is only available on Windows CE. */
|
| ︙ | ︙ | |||
47903 47904 47905 47906 47907 47908 47909 |
#else
{ "CreateEventExW", (SYSCALL)0, 0 },
#endif
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
DWORD,DWORD))aSyscall[62].pCurrent)
| < > | < > > > > | < | 48127 48128 48129 48130 48131 48132 48133 48134 48135 48136 48137 48138 48139 48140 48141 48142 48143 48144 48145 48146 48147 |
#else
{ "CreateEventExW", (SYSCALL)0, 0 },
#endif
#define osCreateEventExW ((HANDLE(WINAPI*)(LPSECURITY_ATTRIBUTES,LPCWSTR, \
DWORD,DWORD))aSyscall[62].pCurrent)
/*
** For WaitForSingleObject(), MSDN says:
**
** Minimum supported client: Windows XP [desktop apps | UWP apps]
** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
*/
{ "WaitForSingleObject", (SYSCALL)WaitForSingleObject, 0 },
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
DWORD))aSyscall[63].pCurrent)
#if !SQLITE_OS_WINCE
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
#else
|
| ︙ | ︙ | |||
48054 48055 48056 48057 48058 48059 48060 48061 48062 48063 48064 48065 48066 48067 |
#else
{ "FlushViewOfFile", (SYSCALL)0, 0 },
#endif
#define osFlushViewOfFile \
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 48280 48281 48282 48283 48284 48285 48286 48287 48288 48289 48290 48291 48292 48293 48294 48295 48296 48297 48298 48299 48300 48301 48302 48303 48304 48305 48306 48307 48308 48309 48310 48311 48312 48313 48314 48315 48316 48317 48318 48319 48320 48321 48322 48323 48324 48325 48326 48327 |
#else
{ "FlushViewOfFile", (SYSCALL)0, 0 },
#endif
#define osFlushViewOfFile \
((BOOL(WINAPI*)(LPCVOID,SIZE_T))aSyscall[79].pCurrent)
/*
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CreateEvent()
** to implement blocking locks with timeouts. MSDN says:
**
** Minimum supported client: Windows XP [desktop apps | UWP apps]
** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
{ "CreateEvent", (SYSCALL)CreateEvent, 0 },
#else
{ "CreateEvent", (SYSCALL)0, 0 },
#endif
#define osCreateEvent ( \
(HANDLE(WINAPI*) (LPSECURITY_ATTRIBUTES,BOOL,BOOL,LPCSTR)) \
aSyscall[80].pCurrent \
)
/*
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined, we require CancelIo()
** for the case where a timeout expires and a lock request must be
** cancelled.
**
** Minimum supported client: Windows XP [desktop apps | UWP apps]
** Minimum supported server: Windows Server 2003 [desktop apps | UWP apps]
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
{ "CancelIo", (SYSCALL)CancelIo, 0 },
#else
{ "CancelIo", (SYSCALL)0, 0 },
#endif
#define osCancelIo ((BOOL(WINAPI*)(HANDLE))aSyscall[81].pCurrent)
}; /* End of the overrideable system calls */
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
|
| ︙ | ︙ | |||
48352 48353 48354 48355 48356 48357 48358 |
osGetVersionExW(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
}
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
| | > > | 48612 48613 48614 48615 48616 48617 48618 48619 48620 48621 48622 48623 48624 48625 48626 48627 48628 |
osGetVersionExW(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
}
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2
|| osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0
;
#else
/*
** NOTE: All sub-platforms where the GetVersionEx[AW] functions are
** deprecated are always assumed to be based on the NT kernel.
*/
return 1;
#endif
|
| ︙ | ︙ | |||
49438 49439 49440 49441 49442 49443 49444 49445 49446 49447 49448 49449 49450 49451 |
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
}else{
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
}
#endif
}
/*
** Unlock a file region.
*/
static BOOL winUnlockFile(
LPHANDLE phFile,
DWORD offsetLow,
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 49700 49701 49702 49703 49704 49705 49706 49707 49708 49709 49710 49711 49712 49713 49714 49715 49716 49717 49718 49719 49720 49721 49722 49723 49724 49725 49726 49727 49728 49729 49730 49731 49732 49733 49734 49735 49736 49737 49738 49739 49740 49741 49742 49743 49744 49745 49746 49747 49748 49749 49750 49751 49752 49753 49754 49755 49756 49757 49758 49759 49760 49761 49762 49763 49764 49765 49766 49767 49768 49769 49770 49771 49772 49773 49774 49775 49776 49777 49778 49779 49780 49781 49782 49783 49784 49785 49786 49787 49788 49789 49790 49791 49792 |
return osLockFileEx(*phFile, flags, 0, numBytesLow, numBytesHigh, &ovlp);
}else{
return osLockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
}
#endif
}
/*
** Lock a region of nByte bytes starting at offset offset of file hFile.
** Take an EXCLUSIVE lock if parameter bExclusive is true, or a SHARED lock
** otherwise. If nMs is greater than zero and the lock cannot be obtained
** immediately, block for that many ms before giving up.
**
** This function returns SQLITE_OK if the lock is obtained successfully. If
** some other process holds the lock, SQLITE_BUSY is returned if nMs==0, or
** SQLITE_BUSY_TIMEOUT otherwise. Or, if an error occurs, SQLITE_IOERR.
*/
static int winHandleLockTimeout(
HANDLE hFile,
DWORD offset,
DWORD nByte,
int bExcl,
DWORD nMs
){
DWORD flags = LOCKFILE_FAIL_IMMEDIATELY | (bExcl?LOCKFILE_EXCLUSIVE_LOCK:0);
int rc = SQLITE_OK;
BOOL ret;
if( !osIsNT() ){
ret = winLockFile(&hFile, flags, offset, 0, nByte, 0);
}else{
OVERLAPPED ovlp;
memset(&ovlp, 0, sizeof(OVERLAPPED));
ovlp.Offset = offset;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( nMs!=0 ){
flags &= ~LOCKFILE_FAIL_IMMEDIATELY;
}
ovlp.hEvent = osCreateEvent(NULL, TRUE, FALSE, NULL);
if( ovlp.hEvent==NULL ){
return SQLITE_IOERR_LOCK;
}
#endif
ret = osLockFileEx(hFile, flags, 0, nByte, 0, &ovlp);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* If SQLITE_ENABLE_SETLK_TIMEOUT is defined, then the file-handle was
** opened with FILE_FLAG_OVERHEAD specified. In this case, the call to
** LockFileEx() may fail because the request is still pending. This can
** happen even if LOCKFILE_FAIL_IMMEDIATELY was specified.
**
** If nMs is 0, then LOCKFILE_FAIL_IMMEDIATELY was set in the flags
** passed to LockFileEx(). In this case, if the operation is pending,
** block indefinitely until it is finished.
**
** Otherwise, wait for up to nMs ms for the operation to finish. nMs
** may be set to INFINITE.
*/
if( !ret && GetLastError()==ERROR_IO_PENDING ){
DWORD nDelay = (nMs==0 ? INFINITE : nMs);
DWORD res = osWaitForSingleObject(ovlp.hEvent, nDelay);
if( res==WAIT_OBJECT_0 ){
ret = TRUE;
}else if( res==WAIT_TIMEOUT ){
rc = SQLITE_BUSY_TIMEOUT;
}else{
/* Some other error has occurred */
rc = SQLITE_IOERR_LOCK;
}
/* If it is still pending, cancel the LockFileEx() call. */
osCancelIo(hFile);
}
osCloseHandle(ovlp.hEvent);
#endif
}
if( rc==SQLITE_OK && !ret ){
rc = SQLITE_BUSY;
}
return rc;
}
/*
** Unlock a file region.
*/
static BOOL winUnlockFile(
LPHANDLE phFile,
DWORD offsetLow,
|
| ︙ | ︙ | |||
49469 49470 49471 49472 49473 49474 49475 49476 49477 49478 49479 49480 49481 49482 49483 49484 49485 49486 49487 49488 49489 |
return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
}else{
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
}
#endif
}
/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/
/*
** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
| > > > > > > > > | > | < > | > > < < < > > | < < < | | | | < < < | | < < < | < < | < | > > | | | | > > > > > > > | > > > > > | < > | 49810 49811 49812 49813 49814 49815 49816 49817 49818 49819 49820 49821 49822 49823 49824 49825 49826 49827 49828 49829 49830 49831 49832 49833 49834 49835 49836 49837 49838 49839 49840 49841 49842 49843 49844 49845 49846 49847 49848 49849 49850 49851 49852 49853 49854 49855 49856 49857 49858 49859 49860 49861 49862 49863 49864 49865 49866 49867 49868 49869 49870 49871 49872 49873 49874 49875 49876 49877 49878 49879 49880 49881 49882 49883 49884 49885 49886 49887 49888 49889 49890 49891 49892 49893 49894 49895 49896 49897 49898 49899 49900 49901 49902 49903 49904 49905 49906 49907 49908 |
return osUnlockFileEx(*phFile, 0, numBytesLow, numBytesHigh, &ovlp);
}else{
return osUnlockFile(*phFile, offsetLow, offsetHigh, numBytesLow,
numBytesHigh);
}
#endif
}
/*
** Remove an nByte lock starting at offset iOff from HANDLE h.
*/
static int winHandleUnlock(HANDLE h, int iOff, int nByte){
BOOL ret = winUnlockFile(&h, iOff, 0, nByte, 0);
return (ret ? SQLITE_OK : SQLITE_IOERR_UNLOCK);
}
/*****************************************************************************
** The next group of routines implement the I/O methods specified
** by the sqlite3_io_methods object.
******************************************************************************/
/*
** Some Microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
** Seek the file handle h to offset nByte of the file.
**
** If successful, return SQLITE_OK. Or, if an error occurs, return an SQLite
** error code.
*/
static int winHandleSeek(HANDLE h, sqlite3_int64 iOffset){
int rc = SQLITE_OK; /* Return value */
#if !SQLITE_OS_WINRT
LONG upperBits; /* Most sig. 32 bits of new offset */
LONG lowerBits; /* Least sig. 32 bits of new offset */
DWORD dwRet; /* Value returned by SetFilePointer() */
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
dwRet = osSetFilePointer(h, lowerBits, &upperBits, FILE_BEGIN);
/* API oddity: If successful, SetFilePointer() returns a dword
** containing the lower 32-bits of the new file-offset. Or, if it fails,
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
** whether an error has actually occurred, it is also necessary to call
** GetLastError(). */
if( dwRet==INVALID_SET_FILE_POINTER ){
DWORD lastErrno = osGetLastError();
if( lastErrno!=NO_ERROR ){
rc = SQLITE_IOERR_SEEK;
}
}
#else
/* This implementation works for WinRT. */
LARGE_INTEGER x; /* The new offset */
BOOL bRet; /* Value returned by SetFilePointerEx() */
x.QuadPart = iOffset;
bRet = osSetFilePointerEx(h, x, 0, FILE_BEGIN);
if(!bRet){
rc = SQLITE_IOERR_SEEK;
}
#endif
OSTRACE(("SEEK file=%p, offset=%lld rc=%s\n", h, iOffset, sqlite3ErrName(rc)));
return rc;
}
/*
** Move the current position of the file handle passed as the first
** argument to offset iOffset within the file. If successful, return 0.
** Otherwise, set pFile->lastErrno and return non-zero.
*/
static int winSeekFile(winFile *pFile, sqlite3_int64 iOffset){
int rc;
rc = winHandleSeek(pFile->h, iOffset);
if( rc!=SQLITE_OK ){
pFile->lastErrno = osGetLastError();
winLogError(rc, pFile->lastErrno, "winSeekFile", pFile->zPath);
}
return rc;
}
#if SQLITE_MAX_MMAP_SIZE>0
/* Forward references to VFS helper methods used for memory mapped files */
static int winMapfile(winFile*, sqlite3_int64);
static int winUnmapfile(winFile*);
#endif
|
| ︙ | ︙ | |||
49801 49802 49803 49804 49805 49806 49807 49808 49809 49810 49811 49812 49813 49814 |
}else{
winLogIoerr(nRetry, __LINE__);
}
OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
/*
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 50154 50155 50156 50157 50158 50159 50160 50161 50162 50163 50164 50165 50166 50167 50168 50169 50170 50171 50172 50173 50174 50175 50176 50177 50178 50179 50180 50181 50182 50183 50184 50185 50186 50187 50188 50189 50190 50191 50192 50193 50194 50195 50196 50197 50198 50199 50200 50201 50202 50203 50204 50205 50206 50207 50208 50209 50210 50211 50212 50213 50214 50215 50216 50217 50218 50219 50220 50221 |
}else{
winLogIoerr(nRetry, __LINE__);
}
OSTRACE(("WRITE pid=%lu, pFile=%p, file=%p, rc=SQLITE_OK\n",
osGetCurrentProcessId(), pFile, pFile->h));
return SQLITE_OK;
}
/*
** Truncate the file opened by handle h to nByte bytes in size.
*/
static int winHandleTruncate(HANDLE h, sqlite3_int64 nByte){
int rc = SQLITE_OK; /* Return code */
rc = winHandleSeek(h, nByte);
if( rc==SQLITE_OK ){
if( 0==osSetEndOfFile(h) ){
rc = SQLITE_IOERR_TRUNCATE;
}
}
return rc;
}
/*
** Determine the size in bytes of the file opened by the handle passed as
** the first argument.
*/
static int winHandleSize(HANDLE h, sqlite3_int64 *pnByte){
int rc = SQLITE_OK;
#if SQLITE_OS_WINRT
FILE_STANDARD_INFO info;
BOOL b;
b = osGetFileInformationByHandleEx(h, FileStandardInfo, &info, sizeof(info));
if( b ){
*pnByte = info.EndOfFile.QuadPart;
}else{
rc = SQLITE_IOERR_FSTAT;
}
#else
DWORD upperBits = 0;
DWORD lowerBits = 0;
assert( pnByte );
lowerBits = osGetFileSize(h, &upperBits);
*pnByte = (((sqlite3_int64)upperBits)<<32) + lowerBits;
if( lowerBits==INVALID_FILE_SIZE && osGetLastError()!=NO_ERROR ){
rc = SQLITE_IOERR_FSTAT;
}
#endif
return rc;
}
/*
** Close the handle passed as the only argument.
*/
static void winHandleClose(HANDLE h){
if( h!=INVALID_HANDLE_VALUE ){
osCloseHandle(h);
}
}
/*
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
|
| ︙ | ︙ | |||
50057 50058 50059 50060 50061 50062 50063 | #endif /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win9x or WinNT. */ | | > | | | 50464 50465 50466 50467 50468 50469 50470 50471 50472 50473 50474 50475 50476 50477 50478 50479 50480 50481 50482 50483 50484 50485 50486 50487 50488 50489 50490 50491 50492 50493 50494 50495 50496 50497 50498 50499 |
#endif
/*
** Acquire a reader lock.
** Different API routines are called depending on whether or not this
** is Win9x or WinNT.
*/
static int winGetReadLock(winFile *pFile, int bBlock){
int res;
DWORD mask = ~(bBlock ? LOCKFILE_FAIL_IMMEDIATELY : 0);
OSTRACE(("READ-LOCK file=%p, lock=%d\n", pFile->h, pFile->locktype));
if( osIsNT() ){
#if SQLITE_OS_WINCE
/*
** NOTE: Windows CE is handled differently here due its lack of the Win32
** API LockFileEx.
*/
res = winceLockFile(&pFile->h, SHARED_FIRST, 0, 1, 0);
#else
res = winLockFile(&pFile->h, SQLITE_LOCKFILEEX_FLAGS&mask, SHARED_FIRST, 0,
SHARED_SIZE, 0);
#endif
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
int lk;
sqlite3_randomness(sizeof(lk), &lk);
pFile->sharedLockByte = (short)((lk & 0x7fffffff)%(SHARED_SIZE - 1));
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS&mask,
SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0);
}
#endif
if( res == 0 ){
pFile->lastErrno = osGetLastError();
/* No need to log a failure to lock */
}
|
| ︙ | ︙ | |||
50172 50173 50174 50175 50176 50177 50178 | /* Make sure the locking sequence is correct */ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); | | | | | > > > > > > > | > | > > | | > > | > > > | < < < > | > > > | 50580 50581 50582 50583 50584 50585 50586 50587 50588 50589 50590 50591 50592 50593 50594 50595 50596 50597 50598 50599 50600 50601 50602 50603 50604 50605 50606 50607 50608 50609 50610 50611 50612 50613 50614 50615 50616 50617 50618 50619 50620 50621 50622 50623 50624 50625 50626 50627 50628 50629 50630 50631 50632 50633 50634 50635 50636 50637 50638 50639 50640 50641 50642 50643 50644 50645 50646 50647 50648 50649 |
/* Make sure the locking sequence is correct
*/
assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
assert( locktype!=PENDING_LOCK );
assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
/* Lock the PENDING_LOCK byte if we need to acquire an EXCLUSIVE lock or
** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of
** the PENDING_LOCK byte is temporary.
*/
newLocktype = pFile->locktype;
if( locktype==SHARED_LOCK
|| (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK)
){
int cnt = 3;
/* Flags for the LockFileEx() call. This should be an exclusive lock if
** this call is to obtain EXCLUSIVE, or a shared lock if this call is to
** obtain SHARED. */
int flags = LOCKFILE_FAIL_IMMEDIATELY;
if( locktype==EXCLUSIVE_LOCK ){
flags |= LOCKFILE_EXCLUSIVE_LOCK;
}
while( cnt>0 ){
/* Try 3 times to get the pending lock. This is needed to work
** around problems caused by indexing and/or anti-virus software on
** Windows systems.
**
** If you are using this code as a model for alternative VFSes, do not
** copy this retry logic. It is a hack intended for Windows only. */
res = winLockFile(&pFile->h, flags, PENDING_BYTE, 0, 1, 0);
if( res ) break;
lastErrno = osGetLastError();
OSTRACE(("LOCK-PENDING-FAIL file=%p, count=%d, result=%d\n",
pFile->h, cnt, res
));
if( lastErrno==ERROR_INVALID_HANDLE ){
pFile->lastErrno = lastErrno;
rc = SQLITE_IOERR_LOCK;
OSTRACE(("LOCK-FAIL file=%p, count=%d, rc=%s\n",
pFile->h, cnt, sqlite3ErrName(rc)
));
return rc;
}
cnt--;
if( cnt>0 ) sqlite3_win32_sleep(1);
}
gotPendingLock = res;
}
/* Acquire a shared lock
*/
if( locktype==SHARED_LOCK && res ){
assert( pFile->locktype==NO_LOCK );
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
res = winGetReadLock(pFile, pFile->bBlockOnConnect);
#else
res = winGetReadLock(pFile, 0);
#endif
if( res ){
newLocktype = SHARED_LOCK;
}else{
lastErrno = osGetLastError();
}
}
|
| ︙ | ︙ | |||
50249 50250 50251 50252 50253 50254 50255 |
(void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
lastErrno = osGetLastError();
| | | 50673 50674 50675 50676 50677 50678 50679 50680 50681 50682 50683 50684 50685 50686 50687 |
(void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
lastErrno = osGetLastError();
winGetReadLock(pFile, 0);
}
}
/* If we are holding a PENDING lock that ought to be released, then
** release it now.
*/
if( gotPendingLock && locktype==SHARED_LOCK ){
|
| ︙ | ︙ | |||
50329 50330 50331 50332 50333 50334 50335 |
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
| | | 50753 50754 50755 50756 50757 50758 50759 50760 50761 50762 50763 50764 50765 50766 50767 |
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
OSTRACE(("UNLOCK file=%p, oldLock=%d(%d), newLock=%d\n",
pFile->h, pFile->locktype, pFile->sharedLockByte, locktype));
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
winUnlockFile(&pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( locktype==SHARED_LOCK && !winGetReadLock(pFile, 0) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
rc = winLogError(SQLITE_IOERR_UNLOCK, osGetLastError(),
"winUnlock", pFile->zPath);
}
}
if( type>=RESERVED_LOCK ){
|
| ︙ | ︙ | |||
50539 50540 50541 50542 50543 50544 50545 50546 50547 50548 50549 50550 50551 50552 |
rc = winMapfile(pFile, -1);
}
}
OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
return rc;
}
#endif
}
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
return SQLITE_NOTFOUND;
}
/*
** Return the sector size in bytes of the underlying block device for
| > > > > > > > > > > > > > > > > > > > > > > | 50963 50964 50965 50966 50967 50968 50969 50970 50971 50972 50973 50974 50975 50976 50977 50978 50979 50980 50981 50982 50983 50984 50985 50986 50987 50988 50989 50990 50991 50992 50993 50994 50995 50996 50997 50998 |
rc = winMapfile(pFile, -1);
}
}
OSTRACE(("FCNTL file=%p, rc=%s\n", pFile->h, sqlite3ErrName(rc)));
return rc;
}
#endif
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
int iNew = *(int*)pArg;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = (iNew < 0) ? INFINITE : (DWORD)iNew;
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
pFile->iBusyTimeout = (DWORD)(!!iNew);
#else
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
case SQLITE_FCNTL_BLOCK_ON_CONNECT: {
int iNew = *(int*)pArg;
pFile->bBlockOnConnect = iNew;
return SQLITE_OK;
}
#endif /* SQLITE_ENABLE_SETLK_TIMEOUT */
}
OSTRACE(("FCNTL file=%p, rc=SQLITE_NOTFOUND\n", pFile->h));
return SQLITE_NOTFOUND;
}
/*
** Return the sector size in bytes of the underlying block device for
|
| ︙ | ︙ | |||
50619 50620 50621 50622 50623 50624 50625 | ** this object or while reading or writing the following fields: ** ** nRef ** pNext ** ** The following fields are read-only after the object is created: ** | < > > > > > | > > < < < | < < < < < | < < < < < > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 51065 51066 51067 51068 51069 51070 51071 51072 51073 51074 51075 51076 51077 51078 51079 51080 51081 51082 51083 51084 51085 51086 51087 51088 51089 51090 51091 51092 51093 51094 51095 51096 51097 51098 51099 51100 51101 51102 51103 51104 51105 51106 51107 51108 51109 51110 51111 51112 51113 51114 51115 51116 51117 51118 51119 51120 51121 51122 51123 51124 51125 51126 51127 51128 51129 51130 51131 51132 51133 51134 51135 51136 51137 51138 51139 51140 51141 51142 |
** this object or while reading or writing the following fields:
**
** nRef
** pNext
**
** The following fields are read-only after the object is created:
**
** zFilename
**
** Either winShmNode.mutex must be held or winShmNode.nRef==0 and
** winShmMutexHeld() is true when reading or writing any other field
** in this structure.
**
** File-handle hSharedShm is used to (a) take the DMS lock, (b) truncate
** the *-shm file if the DMS-locking protocol demands it, and (c) map
** regions of the *-shm file into memory using MapViewOfFile() or
** similar. Other locks are taken by individual clients using the
** winShm.hShm handles.
*/
struct winShmNode {
sqlite3_mutex *mutex; /* Mutex to access this object */
char *zFilename; /* Name of the file */
HANDLE hSharedShm; /* File handle open on zFilename */
int isUnlocked; /* DMS lock has not yet been obtained */
int isReadonly; /* True if read-only */
int szRegion; /* Size of shared-memory regions */
int nRegion; /* Size of array apRegion */
struct ShmRegion {
HANDLE hMap; /* File handle from CreateFileMapping */
void *pMap;
} *aRegion;
DWORD lastErrno; /* The Windows errno from the last I/O error */
int nRef; /* Number of winShm objects pointing to this */
winShmNode *pNext; /* Next in list of all winShmNode objects */
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 nextShmId; /* Next available winShm.id value */
#endif
};
/*
** A global array of all winShmNode objects.
**
** The winShmMutexHeld() must be true while reading or writing this list.
*/
static winShmNode *winShmNodeList = 0;
/*
** Structure used internally by this VFS to record the state of an
** open shared memory connection. There is one such structure for each
** winFile open on a wal mode database.
*/
struct winShm {
winShmNode *pShmNode; /* The underlying winShmNode object */
u16 sharedMask; /* Mask of shared locks held */
u16 exclMask; /* Mask of exclusive locks held */
HANDLE hShm; /* File-handle on *-shm file. For locking. */
int bReadonly; /* True if hShm is opened read-only */
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
u8 id; /* Id of this connection with its winShmNode */
#endif
};
/*
** Constants used for locking
*/
#define WIN_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
#define WIN_SHM_DMS (WIN_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
/* Forward references to VFS methods */
static int winOpen(sqlite3_vfs*,const char*,sqlite3_file*,int,int*);
static int winDelete(sqlite3_vfs *,const char*,int);
/*
** Purge the winShmNodeList list of all entries with winShmNode.nRef==0.
**
|
| ︙ | ︙ | |||
50763 50764 50765 50766 50767 50768 50769 |
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
bRc = osCloseHandle(p->aRegion[i].hMap);
OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
}
| < < | < < | > | < < < < < | > | > > > > > > > > > > > > > > > > > > > > | > > | | > | | > > > > > > > > > > > > > > > > > | > | > > > > > > > > > > > > > > > | > > > > > | > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > | | | > > > > > > < < < < | < > > > > > > > > | < | < | < < < < < < < < < > | < < | | > > > > > > | | > > | > > > < < | | < < < | < | < | < < > | > | > | < | > | > | < < < < < < < < < < < < < < | | < < < | > | < < < < < < < | | | < > > > < | > > > | | < | > > > | > > > > | < < < | < < | > | | < < < < > > | < | < < | < < | > > | | < | > > | | > | < < | < > > < | < < | < | > > > | > | | > | | | < | < > | < | | > | > | | < < < < < < < < | | | < > | > > | | > | 51160 51161 51162 51163 51164 51165 51166 51167 51168 51169 51170 51171 51172 51173 51174 51175 51176 51177 51178 51179 51180 51181 51182 51183 51184 51185 51186 51187 51188 51189 51190 51191 51192 51193 51194 51195 51196 51197 51198 51199 51200 51201 51202 51203 51204 51205 51206 51207 51208 51209 51210 51211 51212 51213 51214 51215 51216 51217 51218 51219 51220 51221 51222 51223 51224 51225 51226 51227 51228 51229 51230 51231 51232 51233 51234 51235 51236 51237 51238 51239 51240 51241 51242 51243 51244 51245 51246 51247 51248 51249 51250 51251 51252 51253 51254 51255 51256 51257 51258 51259 51260 51261 51262 51263 51264 51265 51266 51267 51268 51269 51270 51271 51272 51273 51274 51275 51276 51277 51278 51279 51280 51281 51282 51283 51284 51285 51286 51287 51288 51289 51290 51291 51292 51293 51294 51295 51296 51297 51298 51299 51300 51301 51302 51303 51304 51305 51306 51307 51308 51309 51310 51311 51312 51313 51314 51315 51316 51317 51318 51319 51320 51321 51322 51323 51324 51325 51326 51327 51328 51329 51330 51331 51332 51333 51334 51335 51336 51337 51338 51339 51340 51341 51342 51343 51344 51345 51346 51347 51348 51349 51350 51351 51352 51353 51354 51355 51356 51357 51358 51359 51360 51361 51362 51363 51364 51365 51366 51367 51368 51369 51370 51371 51372 51373 51374 51375 51376 51377 51378 51379 51380 51381 51382 51383 51384 51385 51386 51387 51388 51389 51390 51391 51392 51393 51394 51395 51396 51397 51398 51399 51400 51401 51402 51403 51404 51405 51406 51407 51408 51409 51410 51411 51412 51413 51414 51415 51416 51417 51418 51419 51420 51421 51422 51423 51424 51425 51426 51427 51428 51429 51430 51431 51432 51433 51434 51435 51436 51437 51438 51439 51440 51441 51442 51443 51444 51445 51446 51447 51448 51449 51450 51451 51452 51453 51454 51455 51456 51457 51458 51459 51460 51461 51462 51463 51464 51465 51466 51467 51468 51469 51470 51471 51472 51473 51474 51475 51476 51477 51478 51479 51480 51481 51482 51483 51484 51485 51486 51487 51488 51489 51490 51491 51492 51493 51494 51495 51496 51497 51498 51499 51500 51501 51502 51503 51504 51505 51506 51507 51508 51509 51510 51511 51512 51513 51514 51515 51516 51517 51518 51519 51520 51521 51522 51523 51524 51525 51526 51527 51528 51529 51530 51531 51532 51533 51534 51535 51536 51537 51538 51539 51540 51541 51542 51543 51544 51545 51546 51547 51548 51549 51550 51551 51552 51553 51554 51555 51556 51557 51558 51559 51560 51561 51562 51563 51564 51565 51566 51567 51568 51569 51570 51571 51572 51573 51574 51575 51576 51577 51578 |
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
bRc = osCloseHandle(p->aRegion[i].hMap);
OSTRACE(("SHM-PURGE-CLOSE pid=%lu, region=%d, rc=%s\n",
osGetCurrentProcessId(), i, bRc ? "ok" : "failed"));
UNUSED_VARIABLE_VALUE(bRc);
}
winHandleClose(p->hSharedShm);
if( deleteFlag ){
SimulateIOErrorBenign(1);
sqlite3BeginBenignMalloc();
winDelete(pVfs, p->zFilename, 0);
sqlite3EndBenignMalloc();
SimulateIOErrorBenign(0);
}
*pp = p->pNext;
sqlite3_free(p->aRegion);
sqlite3_free(p);
}else{
pp = &p->pNext;
}
}
}
/*
** The DMS lock has not yet been taken on the shm file associated with
** pShmNode. Take the lock. Truncate the *-shm file if required.
** Return SQLITE_OK if successful, or an SQLite error code otherwise.
*/
static int winLockSharedMemory(winShmNode *pShmNode, DWORD nMs){
HANDLE h = pShmNode->hSharedShm;
int rc = SQLITE_OK;
assert( sqlite3_mutex_held(pShmNode->mutex) );
rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 1, 0);
if( rc==SQLITE_OK ){
/* We have an EXCLUSIVE lock on the DMS byte. This means that this
** is the first process to open the file. Truncate it to zero bytes
** in this case. */
if( pShmNode->isReadonly ){
rc = SQLITE_READONLY_CANTINIT;
}else{
rc = winHandleTruncate(h, 0);
}
/* Release the EXCLUSIVE lock acquired above. */
winUnlockFile(&h, WIN_SHM_DMS, 0, 1, 0);
}else if( (rc & 0xFF)==SQLITE_BUSY ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
/* Take a SHARED lock on the DMS byte. */
rc = winHandleLockTimeout(h, WIN_SHM_DMS, 1, 0, nMs);
if( rc==SQLITE_OK ){
pShmNode->isUnlocked = 0;
}
}
return rc;
}
/*
** Convert a UTF-8 filename into whatever form the underlying
** operating system wants filenames in. Space to hold the result
** is obtained from malloc and must be freed by the calling
** function.
*/
static void *winConvertFromUtf8Filename(const char *zFilename){
void *zConverted = 0;
if( osIsNT() ){
zConverted = winUtf8ToUnicode(zFilename);
}
#ifdef SQLITE_WIN32_HAS_ANSI
else{
zConverted = winUtf8ToMbcs(zFilename, osAreFileApisANSI());
}
#endif
/* caller will handle out of memory */
return zConverted;
}
/*
** This function is used to open a handle on a *-shm file.
**
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined at build time, then the file
** is opened with FILE_FLAG_OVERLAPPED specified. If not, it is not.
*/
static int winHandleOpen(
const char *zUtf8, /* File to open */
int *pbReadonly, /* IN/OUT: True for readonly handle */
HANDLE *ph /* OUT: New HANDLE for file */
){
int rc = SQLITE_OK;
void *zConverted = 0;
int bReadonly = *pbReadonly;
HANDLE h = INVALID_HANDLE_VALUE;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
const DWORD flag_overlapped = FILE_FLAG_OVERLAPPED;
#else
const DWORD flag_overlapped = 0;
#endif
/* Convert the filename to the system encoding. */
zConverted = winConvertFromUtf8Filename(zUtf8);
if( zConverted==0 ){
OSTRACE(("OPEN name=%s, rc=SQLITE_IOERR_NOMEM", zUtf8));
rc = SQLITE_IOERR_NOMEM_BKPT;
goto winopenfile_out;
}
/* Ensure the file we are trying to open is not actually a directory. */
if( winIsDir(zConverted) ){
OSTRACE(("OPEN name=%s, rc=SQLITE_CANTOPEN_ISDIR", zUtf8));
rc = SQLITE_CANTOPEN_ISDIR;
goto winopenfile_out;
}
/* TODO: platforms.
** TODO: retry-on-ioerr.
*/
if( osIsNT() ){
#if SQLITE_OS_WINRT
CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
memset(&extendedParameters, 0, sizeof(extendedParameters));
extendedParameters.dwSize = sizeof(extendedParameters);
extendedParameters.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
extendedParameters.dwFileFlags = flag_overlapped;
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
h = osCreateFile2((LPCWSTR)zConverted,
(GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)),/* dwDesiredAccess */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
OPEN_ALWAYS, /* dwCreationDisposition */
&extendedParameters
);
#else
h = osCreateFileW((LPCWSTR)zConverted, /* lpFileName */
(GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
NULL, /* lpSecurityAttributes */
OPEN_ALWAYS, /* dwCreationDisposition */
FILE_ATTRIBUTE_NORMAL|flag_overlapped,
NULL
);
#endif
}else{
/* Due to pre-processor directives earlier in this file,
** SQLITE_WIN32_HAS_ANSI is always defined if osIsNT() is false. */
#ifdef SQLITE_WIN32_HAS_ANSI
h = osCreateFileA((LPCSTR)zConverted,
(GENERIC_READ | (bReadonly ? 0 : GENERIC_WRITE)), /* dwDesiredAccess */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* dwShareMode */
NULL, /* lpSecurityAttributes */
OPEN_ALWAYS, /* dwCreationDisposition */
FILE_ATTRIBUTE_NORMAL|flag_overlapped,
NULL
);
#endif
}
if( h==INVALID_HANDLE_VALUE ){
if( bReadonly==0 ){
bReadonly = 1;
rc = winHandleOpen(zUtf8, &bReadonly, &h);
}else{
rc = SQLITE_CANTOPEN_BKPT;
}
}
winopenfile_out:
sqlite3_free(zConverted);
*pbReadonly = bReadonly;
*ph = h;
return rc;
}
/*
** Open the shared-memory area associated with database file pDbFd.
*/
static int winOpenSharedMemory(winFile *pDbFd){
struct winShm *p; /* The connection to be opened */
winShmNode *pShmNode = 0; /* The underlying mmapped file */
int rc = SQLITE_OK; /* Result code */
winShmNode *pNew; /* Newly allocated winShmNode */
int nName; /* Size of zName in bytes */
assert( pDbFd->pShm==0 ); /* Not previously opened */
/* Allocate space for the new sqlite3_shm object. Also speculatively
** allocate space for a new winShmNode and filename. */
p = sqlite3MallocZero( sizeof(*p) );
if( p==0 ) return SQLITE_IOERR_NOMEM_BKPT;
nName = sqlite3Strlen30(pDbFd->zPath);
pNew = sqlite3MallocZero( sizeof(*pShmNode) + (i64)nName + 17 );
if( pNew==0 ){
sqlite3_free(p);
return SQLITE_IOERR_NOMEM_BKPT;
}
pNew->zFilename = (char*)&pNew[1];
pNew->hSharedShm = INVALID_HANDLE_VALUE;
pNew->isUnlocked = 1;
sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath);
sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename);
/* Open a file-handle on the *-shm file for this connection. This file-handle
** is only used for locking. The mapping of the *-shm file is created using
** the shared file handle in winShmNode.hSharedShm. */
p->bReadonly = sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0);
rc = winHandleOpen(pNew->zFilename, &p->bReadonly, &p->hShm);
/* Look to see if there is an existing winShmNode that can be used.
** If no matching winShmNode currently exists, then create a new one. */
winShmEnterMutex();
for(pShmNode = winShmNodeList; pShmNode; pShmNode=pShmNode->pNext){
/* TBD need to come up with better match here. Perhaps
** use FILE_ID_BOTH_DIR_INFO Structure. */
if( sqlite3StrICmp(pShmNode->zFilename, pNew->zFilename)==0 ) break;
}
if( pShmNode==0 ){
pShmNode = pNew;
/* Allocate a mutex for this winShmNode object, if one is required. */
if( sqlite3GlobalConfig.bCoreMutex ){
pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->mutex==0 ) rc = SQLITE_IOERR_NOMEM_BKPT;
}
/* Open a file-handle to use for mappings, and for the DMS lock. */
if( rc==SQLITE_OK ){
HANDLE h = INVALID_HANDLE_VALUE;
pShmNode->isReadonly = p->bReadonly;
rc = winHandleOpen(pNew->zFilename, &pShmNode->isReadonly, &h);
pShmNode->hSharedShm = h;
}
/* If successful, link the new winShmNode into the global list. If an
** error occurred, free the object. */
if( rc==SQLITE_OK ){
pShmNode->pNext = winShmNodeList;
winShmNodeList = pShmNode;
pNew = 0;
}else{
sqlite3_mutex_free(pShmNode->mutex);
if( pShmNode->hSharedShm!=INVALID_HANDLE_VALUE ){
osCloseHandle(pShmNode->hSharedShm);
}
}
}
/* If no error has occurred, link the winShm object to the winShmNode and
** the winShm to pDbFd. */
if( rc==SQLITE_OK ){
p->pShmNode = pShmNode;
pShmNode->nRef++;
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
p->id = pShmNode->nextShmId++;
#endif
pDbFd->pShm = p;
}else if( p ){
winHandleClose(p->hShm);
sqlite3_free(p);
}
assert( rc!=SQLITE_OK || pShmNode->isUnlocked==0 || pShmNode->nRegion==0 );
winShmLeaveMutex();
sqlite3_free(pNew);
return rc;
}
/*
** Close a connection to shared-memory. Delete the underlying
** storage if deleteFlag is true.
*/
static int winShmUnmap(
sqlite3_file *fd, /* Database holding shared memory */
int deleteFlag /* Delete after closing if true */
){
winFile *pDbFd; /* Database holding shared-memory */
winShm *p; /* The connection to be closed */
winShmNode *pShmNode; /* The underlying shared-memory file */
pDbFd = (winFile*)fd;
p = pDbFd->pShm;
if( p==0 ) return SQLITE_OK;
if( p->hShm!=INVALID_HANDLE_VALUE ){
osCloseHandle(p->hShm);
}
pShmNode = p->pShmNode;
winShmEnterMutex();
/* If pShmNode->nRef has reached 0, then close the underlying
** shared-memory file, too. */
assert( pShmNode->nRef>0 );
pShmNode->nRef--;
if( pShmNode->nRef==0 ){
winShmPurge(pDbFd->pVfs, deleteFlag);
}
winShmLeaveMutex();
/* Free the connection p */
sqlite3_free(p);
pDbFd->pShm = 0;
return SQLITE_OK;
}
/*
** Change the lock state for a shared-memory segment.
*/
static int winShmLock(
sqlite3_file *fd, /* Database file holding the shared memory */
int ofst, /* First lock to acquire or release */
int n, /* Number of locks to acquire or release */
int flags /* What to do with the lock */
){
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
winShm *p = pDbFd->pShm; /* The shared memory being locked */
winShmNode *pShmNode;
int rc = SQLITE_OK; /* Result code */
u16 mask = (u16)((1U<<(ofst+n)) - (1U<<ofst)); /* Mask of locks to [un]take */
if( p==0 ) return SQLITE_IOERR_SHMLOCK;
pShmNode = p->pShmNode;
if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
assert( n>=1 );
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED)
|| flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) );
assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 );
/* Check that, if this to be a blocking lock, no locks that occur later
** in the following list than the lock being obtained are already held:
**
** 1. Checkpointer lock (ofst==1).
** 2. Write lock (ofst==0).
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
**
** In other words, if this is a blocking lock, none of the locks that
** occur later in the above list than the lock being obtained may be
** held.
**
** It is not permitted to block on the RECOVER lock.
*/
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && defined(SQLITE_DEBUG)
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
(ofst!=2) /* not RECOVER */
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
));
}
#endif
/* Check if there is any work to do. There are three cases:
**
** a) An unlock operation where there are locks to unlock,
** b) An shared lock where the requested lock is not already held
** c) An exclusive lock where the requested lock is not already held
**
** The SQLite core never requests an exclusive lock that it already holds.
** This is assert()ed immediately below. */
assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
|| 0==(p->exclMask & mask)
);
if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
|| (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
|| (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
){
if( flags & SQLITE_SHM_UNLOCK ){
/* Case (a) - unlock. */
assert( (p->exclMask & p->sharedMask)==0 );
assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
rc = winHandleUnlock(p->hShm, ofst+WIN_SHM_BASE, n);
/* If successful, also clear the bits in sharedMask/exclMask */
if( rc==SQLITE_OK ){
p->exclMask = (p->exclMask & ~mask);
p->sharedMask = (p->sharedMask & ~mask);
}
}else{
int bExcl = ((flags & SQLITE_SHM_EXCLUSIVE) ? 1 : 0);
DWORD nMs = winFileBusyTimeout(pDbFd);
rc = winHandleLockTimeout(p->hShm, ofst+WIN_SHM_BASE, n, bExcl, nMs);
if( rc==SQLITE_OK ){
if( bExcl ){
p->exclMask = (p->exclMask | mask);
}else{
p->sharedMask = (p->sharedMask | mask);
}
}
}
}
OSTRACE((
"SHM-LOCK(%d,%d,%d) pid=%lu, id=%d, sharedMask=%03x, exclMask=%03x,"
" rc=%s\n",
ofst, n, flags,
osGetCurrentProcessId(), p->id, p->sharedMask, p->exclMask,
sqlite3ErrName(rc))
);
return rc;
}
/*
** Implement a memory barrier or memory fence on shared memory.
**
** All loads and stores begun before the barrier must complete before
|
| ︙ | ︙ | |||
51137 51138 51139 51140 51141 51142 51143 |
pShm = pDbFd->pShm;
assert( pShm!=0 );
}
pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->isUnlocked ){
| > > | < < > > | < | | < | < | | | < < | < < | < < > | 51626 51627 51628 51629 51630 51631 51632 51633 51634 51635 51636 51637 51638 51639 51640 51641 51642 51643 51644 51645 51646 51647 51648 51649 51650 51651 51652 51653 51654 51655 51656 51657 51658 51659 51660 51661 51662 51663 51664 51665 51666 51667 51668 51669 51670 51671 51672 51673 51674 51675 51676 51677 51678 51679 51680 51681 51682 51683 51684 51685 51686 51687 51688 51689 51690 51691 51692 51693 51694 51695 51696 51697 51698 51699 51700 51701 51702 51703 51704 51705 |
pShm = pDbFd->pShm;
assert( pShm!=0 );
}
pShmNode = pShm->pShmNode;
sqlite3_mutex_enter(pShmNode->mutex);
if( pShmNode->isUnlocked ){
/* Take the DMS lock. */
assert( pShmNode->nRegion==0 );
rc = winLockSharedMemory(pShmNode, winFileBusyTimeout(pDbFd));
if( rc!=SQLITE_OK ) goto shmpage_out;
}
assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 );
if( pShmNode->nRegion<=iRegion ){
HANDLE hShared = pShmNode->hSharedShm;
struct ShmRegion *apNew; /* New aRegion[] array */
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
sqlite3_int64 sz; /* Current size of wal-index file */
pShmNode->szRegion = szRegion;
/* The requested region is not mapped into this processes address space.
** Check to see if it has been allocated (i.e. if the wal-index file is
** large enough to contain the requested region).
*/
rc = winHandleSize(hShared, &sz);
if( rc!=SQLITE_OK ){
rc = winLogError(rc, osGetLastError(), "winShmMap1", pDbFd->zPath);
goto shmpage_out;
}
if( sz<nByte ){
/* The requested memory region does not exist. If isWrite is set to
** zero, exit early. *pp will be set to NULL and SQLITE_OK returned.
**
** Alternatively, if isWrite is non-zero, use ftruncate() to allocate
** the requested memory region. */
if( !isWrite ) goto shmpage_out;
rc = winHandleTruncate(hShared, nByte);
if( rc!=SQLITE_OK ){
rc = winLogError(rc, osGetLastError(), "winShmMap2", pDbFd->zPath);
goto shmpage_out;
}
}
/* Map the requested memory region into this processes address space. */
apNew = (struct ShmRegion*)sqlite3_realloc64(
pShmNode->aRegion, (iRegion+1)*sizeof(apNew[0])
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM_BKPT;
goto shmpage_out;
}
pShmNode->aRegion = apNew;
if( pShmNode->isReadonly ){
protect = PAGE_READONLY;
flags = FILE_MAP_READ;
}
while( pShmNode->nRegion<=iRegion ){
HANDLE hMap = NULL; /* file-mapping handle */
void *pMap = 0; /* Mapped memory region */
#if SQLITE_OS_WINRT
hMap = osCreateFileMappingFromApp(hShared, NULL, protect, nByte, NULL);
#elif defined(SQLITE_WIN32_HAS_WIDE)
hMap = osCreateFileMappingW(hShared, NULL, protect, 0, nByte, NULL);
#elif defined(SQLITE_WIN32_HAS_ANSI) && SQLITE_WIN32_CREATEFILEMAPPINGA
hMap = osCreateFileMappingA(hShared, NULL, protect, 0, nByte, NULL);
#endif
OSTRACE(("SHM-MAP-CREATE pid=%lu, region=%d, size=%d, rc=%s\n",
osGetCurrentProcessId(), pShmNode->nRegion, nByte,
hMap ? "ok" : "failed"));
if( hMap ){
int iOffset = pShmNode->nRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
#if SQLITE_OS_WINRT
|
| ︙ | ︙ | |||
51251 51252 51253 51254 51255 51256 51257 |
int iOffset = iRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
char *p = (char *)pShmNode->aRegion[iRegion].pMap;
*pp = (void *)&p[iOffsetShift];
}else{
*pp = 0;
}
| | > > | 51734 51735 51736 51737 51738 51739 51740 51741 51742 51743 51744 51745 51746 51747 51748 51749 51750 |
int iOffset = iRegion*szRegion;
int iOffsetShift = iOffset % winSysInfo.dwAllocationGranularity;
char *p = (char *)pShmNode->aRegion[iRegion].pMap;
*pp = (void *)&p[iOffsetShift];
}else{
*pp = 0;
}
if( pShmNode->isReadonly && rc==SQLITE_OK ){
rc = SQLITE_READONLY;
}
sqlite3_mutex_leave(pShmNode->mutex);
return rc;
}
#else
# define winShmMap 0
# define winShmLock 0
|
| ︙ | ︙ | |||
51592 51593 51594 51595 51596 51597 51598 | } #endif /* caller will handle out of memory */ return zConverted; } #endif | < < < < < < < < < < < < < < < < < < < < | 52077 52078 52079 52080 52081 52082 52083 52084 52085 52086 52087 52088 52089 52090 |
}
#endif
/* caller will handle out of memory */
return zConverted;
}
#endif
/*
** This function returns non-zero if the specified UTF-8 string buffer
** ends with a directory separator character or one was successfully
** added to it.
*/
static int winMakeEndInDirSep(int nBuf, char *zBuf){
if( zBuf ){
|
| ︙ | ︙ | |||
53065 53066 53067 53068 53069 53070 53071 |
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
| | | 53530 53531 53532 53533 53534 53535 53536 53537 53538 53539 53540 53541 53542 53543 53544 |
winGetSystemCall, /* xGetSystemCall */
winNextSystemCall, /* xNextSystemCall */
};
#endif
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==82 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT
osGetNativeSystemInfo(&winSysInfo);
#else
osGetSystemInfo(&winSysInfo);
|
| ︙ | ︙ | |||
54123 54124 54125 54126 54127 54128 54129 | #define BITVEC_MXHASH (BITVEC_NINT/2) /* Hashing function for the aHash representation. ** Empirical testing showed that the *37 multiplier ** (an arbitrary prime)in the hash function provided ** no fewer collisions than the no-op *1. */ #define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) | | | 54588 54589 54590 54591 54592 54593 54594 54595 54596 54597 54598 54599 54600 54601 54602 | #define BITVEC_MXHASH (BITVEC_NINT/2) /* Hashing function for the aHash representation. ** Empirical testing showed that the *37 multiplier ** (an arbitrary prime)in the hash function provided ** no fewer collisions than the no-op *1. */ #define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT) #define BITVEC_NPTR ((u32)(BITVEC_USIZE/sizeof(Bitvec *))) /* ** A bitmap is an instance of the following structure. ** ** This bitmap records the existence of zero or more bits ** with values between 1 and iSize, inclusive. |
| ︙ | ︙ | |||
54306 54307 54308 54309 54310 54311 54312 |
i = i%p->iDivisor;
p = p->u.apSub[bin];
if (!p) {
return;
}
}
if( p->iSize<=BITVEC_NBIT ){
| | | 54771 54772 54773 54774 54775 54776 54777 54778 54779 54780 54781 54782 54783 54784 54785 |
i = i%p->iDivisor;
p = p->u.apSub[bin];
if (!p) {
return;
}
}
if( p->iSize<=BITVEC_NBIT ){
p->u.aBitmap[i/BITVEC_SZELEM] &= ~(BITVEC_TELEM)(1<<(i&(BITVEC_SZELEM-1)));
}else{
unsigned int j;
u32 *aiValues = pBuf;
memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash));
memset(p->u.aHash, 0, sizeof(p->u.aHash));
p->nSet = 0;
for(j=0; j<BITVEC_NINT; j++){
|
| ︙ | ︙ | |||
54357 54358 54359 54360 54361 54362 54363 | /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=I<N. ** Then the following macros can be used to set, clear, or test ** individual bits within V. */ #define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) | | | 54822 54823 54824 54825 54826 54827 54828 54829 54830 54831 54832 54833 54834 54835 54836 | /* ** Let V[] be an array of unsigned characters sufficient to hold ** up to N bits. Let I be an integer between 0 and N. 0<=I<N. ** Then the following macros can be used to set, clear, or test ** individual bits within V. */ #define SETBIT(V,I) V[I>>3] |= (1<<(I&7)) #define CLEARBIT(V,I) V[I>>3] &= ~(BITVEC_TELEM)(1<<(I&7)) #define TESTBIT(V,I) (V[I>>3]&(1<<(I&7)))!=0 /* ** This routine runs an extensive test of the Bitvec code. ** ** The input is an array of integers that acts as a program ** to test the Bitvec. The integers are opcodes followed |
| ︙ | ︙ | |||
55641 55642 55643 55644 55645 55646 55647 | int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of global page cache memory */ /* Above requires no mutex. Use mutex below for variable that follow. */ sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ | < < < < | 56106 56107 56108 56109 56110 56111 56112 56113 56114 56115 56116 56117 56118 56119 | int nSlot; /* The number of pcache slots */ int nReserve; /* Try to keep nFreeSlot above this */ void *pStart, *pEnd; /* Bounds of global page cache memory */ /* Above requires no mutex. Use mutex below for variable that follow. */ sqlite3_mutex *mutex; /* Mutex for accessing the following: */ PgFreeslot *pFree; /* Free page blocks */ int nFreeSlot; /* Number of unused pcache slots */ int bUnderPressure; /* True if low on PAGECACHE memory */ } pcache1_g; /* ** All code in this file should access the global structure above via the ** alias "pcache1". This ensures that the WSD emulation is used when ** compiling for systems that do not support real WSD. |
| ︙ | ︙ | |||
55692 55693 55694 55695 55696 55697 55698 |
if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
pcache1.pStart = pBuf;
pcache1.pFree = 0;
| | | 56153 56154 56155 56156 56157 56158 56159 56160 56161 56162 56163 56164 56165 56166 56167 |
if( n==0 ) sz = 0;
sz = ROUNDDOWN8(sz);
pcache1.szSlot = sz;
pcache1.nSlot = pcache1.nFreeSlot = n;
pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
pcache1.pStart = pBuf;
pcache1.pFree = 0;
AtomicStore(&pcache1.bUnderPressure,0);
while( n-- ){
p = (PgFreeslot*)pBuf;
p->pNext = pcache1.pFree;
pcache1.pFree = p;
pBuf = (void*)&((char*)pBuf)[sz];
}
pcache1.pEnd = pBuf;
|
| ︙ | ︙ | |||
55760 55761 55762 55763 55764 55765 55766 |
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
if( p ){
pcache1.pFree = pcache1.pFree->pNext;
pcache1.nFreeSlot--;
| | | 56221 56222 56223 56224 56225 56226 56227 56228 56229 56230 56231 56232 56233 56234 56235 |
assert( sqlite3_mutex_notheld(pcache1.grp.mutex) );
if( nByte<=pcache1.szSlot ){
sqlite3_mutex_enter(pcache1.mutex);
p = (PgHdr1 *)pcache1.pFree;
if( p ){
pcache1.pFree = pcache1.pFree->pNext;
pcache1.nFreeSlot--;
AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
assert( pcache1.nFreeSlot>=0 );
sqlite3StatusHighwater(SQLITE_STATUS_PAGECACHE_SIZE, nByte);
sqlite3StatusUp(SQLITE_STATUS_PAGECACHE_USED, 1);
}
sqlite3_mutex_leave(pcache1.mutex);
}
if( p==0 ){
|
| ︙ | ︙ | |||
55799 55800 55801 55802 55803 55804 55805 |
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
pcache1.nFreeSlot++;
| | | 56260 56261 56262 56263 56264 56265 56266 56267 56268 56269 56270 56271 56272 56273 56274 |
PgFreeslot *pSlot;
sqlite3_mutex_enter(pcache1.mutex);
sqlite3StatusDown(SQLITE_STATUS_PAGECACHE_USED, 1);
pSlot = (PgFreeslot*)p;
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
pcache1.nFreeSlot++;
AtomicStore(&pcache1.bUnderPressure,pcache1.nFreeSlot<pcache1.nReserve);
assert( pcache1.nFreeSlot<=pcache1.nSlot );
sqlite3_mutex_leave(pcache1.mutex);
}else{
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
#ifndef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
{
|
| ︙ | ︙ | |||
55930 55931 55932 55933 55934 55935 55936 |
** Or, the heap is used for all page cache memory but the heap is
** under memory pressure, then again it is desirable to avoid
** allocating a new page cache entry in order to avoid stressing
** the heap even further.
*/
static int pcache1UnderMemoryPressure(PCache1 *pCache){
if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
| | | 56391 56392 56393 56394 56395 56396 56397 56398 56399 56400 56401 56402 56403 56404 56405 |
** Or, the heap is used for all page cache memory but the heap is
** under memory pressure, then again it is desirable to avoid
** allocating a new page cache entry in order to avoid stressing
** the heap even further.
*/
static int pcache1UnderMemoryPressure(PCache1 *pCache){
if( pcache1.nSlot && (pCache->szPage+pCache->szExtra)<=pcache1.szSlot ){
return AtomicLoad(&pcache1.bUnderPressure);
}else{
return sqlite3HeapNearlyFull();
}
}
/******************************************************************************/
/******** General Implementation Functions ************************************/
|
| ︙ | ︙ | |||
59209 59210 59211 59212 59213 59214 59215 59216 59217 59218 59219 59220 59221 59222 |
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
releaseAllSavepoints(pPager);
if( pagerUseWal(pPager) ){
assert( !isOpen(pPager->jfd) );
sqlite3WalEndReadTransaction(pPager->pWal);
pPager->eState = PAGER_OPEN;
}else if( !pPager->exclusiveMode ){
int rc; /* Error code returned by pagerUnlockDb() */
int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
/* If the operating system support deletion of open files, then
| > > > > > > > > > | 59670 59671 59672 59673 59674 59675 59676 59677 59678 59679 59680 59681 59682 59683 59684 59685 59686 59687 59688 59689 59690 59691 59692 |
sqlite3BitvecDestroy(pPager->pInJournal);
pPager->pInJournal = 0;
releaseAllSavepoints(pPager);
if( pagerUseWal(pPager) ){
assert( !isOpen(pPager->jfd) );
if( pPager->eState==PAGER_ERROR ){
/* If an IO error occurs in wal.c while attempting to wrap the wal file,
** then the Wal object may be holding a write-lock but no read-lock.
** This call ensures that the write-lock is dropped as well. We cannot
** have sqlite3WalEndReadTransaction() drop the write-lock, as it once
** did, because this would break "BEGIN EXCLUSIVE" handling for
** SQLITE_ENABLE_SETLK_TIMEOUT builds. */
sqlite3WalEndWriteTransaction(pPager->pWal);
}
sqlite3WalEndReadTransaction(pPager->pWal);
pPager->eState = PAGER_OPEN;
}else if( !pPager->exclusiveMode ){
int rc; /* Error code returned by pagerUnlockDb() */
int iDc = isOpen(pPager->fd)?sqlite3OsDeviceCharacteristics(pPager->fd):0;
/* If the operating system support deletion of open files, then
|
| ︙ | ︙ | |||
65667 65668 65669 65670 65671 65672 65673 65674 65675 65676 65677 65678 65679 65680 |
#define walFrameOffset(iFrame, szPage) ( \
WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
)
/*
** An open write-ahead log file is represented by an instance of the
** following object.
*/
struct Wal {
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
sqlite3_file *pDbFd; /* File handle for the database file */
sqlite3_file *pWalFd; /* File handle for WAL file */
u32 iCallback; /* Value to pass to log callback (or 0) */
i64 mxWalSize; /* Truncate WAL to this size upon reset */
| > > > > > | 66137 66138 66139 66140 66141 66142 66143 66144 66145 66146 66147 66148 66149 66150 66151 66152 66153 66154 66155 |
#define walFrameOffset(iFrame, szPage) ( \
WAL_HDRSIZE + ((iFrame)-1)*(i64)((szPage)+WAL_FRAME_HDRSIZE) \
)
/*
** An open write-ahead log file is represented by an instance of the
** following object.
**
** writeLock:
** This is usually set to 1 whenever the WRITER lock is held. However,
** if it is set to 2, then the WRITER lock is held but must be released
** by walHandleException() if a SEH exception is thrown.
*/
struct Wal {
sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */
sqlite3_file *pDbFd; /* File handle for the database file */
sqlite3_file *pWalFd; /* File handle for WAL file */
u32 iCallback; /* Value to pass to log callback (or 0) */
i64 mxWalSize; /* Truncate WAL to this size upon reset */
|
| ︙ | ︙ | |||
65757 65758 65759 65760 65761 65762 65763 |
int nSegment; /* Number of entries in aSegment[] */
struct WalSegment {
int iNext; /* Next slot in aIndex[] not yet returned */
ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
u32 *aPgno; /* Array of page numbers. */
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
int iZero; /* Frame number associated with aPgno[0] */
| | > > > > | 66232 66233 66234 66235 66236 66237 66238 66239 66240 66241 66242 66243 66244 66245 66246 66247 66248 66249 66250 66251 |
int nSegment; /* Number of entries in aSegment[] */
struct WalSegment {
int iNext; /* Next slot in aIndex[] not yet returned */
ht_slot *aIndex; /* i0, i1, i2... such that aPgno[iN] ascend */
u32 *aPgno; /* Array of page numbers. */
int nEntry; /* Nr. of entries in aPgno[] and aIndex[] */
int iZero; /* Frame number associated with aPgno[0] */
} aSegment[FLEXARRAY]; /* One for every 32KB page in the wal-index */
};
/* Size (in bytes) of a WalIterator object suitable for N or fewer segments */
#define SZ_WALITERATOR(N) \
(offsetof(WalIterator,aSegment)*(N)*sizeof(struct WalSegment))
/*
** Define the parameters of the hash tables in the wal-index file. There
** is a hash-table following every HASHTABLE_NPAGE page numbers in the
** wal-index.
**
** Changing any of these constants will alter the wal-index format and
|
| ︙ | ︙ | |||
67120 67121 67122 67123 67124 67125 67126 | ** it only runs if there is actually content in the log (mxFrame>0). */ assert( pWal->ckptLock && pWal->hdr.mxFrame>0 ); iLast = pWal->hdr.mxFrame; /* Allocate space for the WalIterator object. */ nSegment = walFramePage(iLast) + 1; | | < | 67599 67600 67601 67602 67603 67604 67605 67606 67607 67608 67609 67610 67611 67612 67613 |
** it only runs if there is actually content in the log (mxFrame>0).
*/
assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
iLast = pWal->hdr.mxFrame;
/* Allocate space for the WalIterator object. */
nSegment = walFramePage(iLast) + 1;
nByte = SZ_WALITERATOR(nSegment)
+ iLast*sizeof(ht_slot);
p = (WalIterator *)sqlite3_malloc64(nByte
+ sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
);
if( !p ){
return SQLITE_NOMEM_BKPT;
}
|
| ︙ | ︙ | |||
67192 67193 67194 67195 67196 67197 67198 |
** they are supported by the VFS, and (b) the database handle is configured
** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
** or 0 otherwise.
*/
static int walEnableBlocking(Wal *pWal){
int res = 0;
if( pWal->db ){
| | | 67670 67671 67672 67673 67674 67675 67676 67677 67678 67679 67680 67681 67682 67683 67684 |
** they are supported by the VFS, and (b) the database handle is configured
** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
** or 0 otherwise.
*/
static int walEnableBlocking(Wal *pWal){
int res = 0;
if( pWal->db ){
int tmout = pWal->db->setlkTimeout;
if( tmout ){
res = walEnableBlockingMs(pWal, tmout);
}
}
return res;
}
|
| ︙ | ︙ | |||
67578 67579 67580 67581 67582 67583 67584 |
** 4) Returns SQLITE_IOERR.
*/
static int walHandleException(Wal *pWal){
if( pWal->exclusiveMode==0 ){
static const int S = 1;
static const int E = (1<<SQLITE_SHM_NLOCK);
int ii;
| > > | | 68056 68057 68058 68059 68060 68061 68062 68063 68064 68065 68066 68067 68068 68069 68070 68071 68072 |
** 4) Returns SQLITE_IOERR.
*/
static int walHandleException(Wal *pWal){
if( pWal->exclusiveMode==0 ){
static const int S = 1;
static const int E = (1<<SQLITE_SHM_NLOCK);
int ii;
u32 mUnlock;
if( pWal->writeLock==2 ) pWal->writeLock = 0;
mUnlock = pWal->lockMask & ~(
(pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
| (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
| (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
);
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
if( (S<<ii) & mUnlock ) walUnlockShared(pWal, ii);
if( (E<<ii) & mUnlock ) walUnlockExclusive(pWal, ii, 1);
|
| ︙ | ︙ | |||
67850 67851 67852 67853 67854 67855 67856 |
rc = SQLITE_READONLY_RECOVERY;
}
}else{
int bWriteLock = pWal->writeLock;
if( bWriteLock
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
){
| > > > > > | | 68330 68331 68332 68333 68334 68335 68336 68337 68338 68339 68340 68341 68342 68343 68344 68345 68346 68347 68348 68349 |
rc = SQLITE_READONLY_RECOVERY;
}
}else{
int bWriteLock = pWal->writeLock;
if( bWriteLock
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
){
/* If the write-lock was just obtained, set writeLock to 2 instead of
** the usual 1. This causes walIndexPage() to behave as if the
** write-lock were held (so that it allocates new pages as required),
** and walHandleException() to unlock the write-lock if a SEH exception
** is thrown. */
if( !bWriteLock ) pWal->writeLock = 2;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
if( badHdr ){
/* If the wal-index header is still malformed even while holding
** a WRITE lock, it can only mean that the header is corrupted and
** needs to be reconstructed. So run recovery to do exactly that.
** Disable blocking locks first. */
|
| ︙ | ︙ | |||
68635 68636 68637 68638 68639 68640 68641 |
}
/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
| > | > > | 69120 69121 69122 69123 69124 69125 69126 69127 69128 69129 69130 69131 69132 69133 69134 69135 69136 69137 69138 |
}
/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
#ifndef SQLITE_ENABLE_SETLK_TIMEOUT
assert( pWal->writeLock==0 || pWal->readLock<0 );
#endif
if( pWal->readLock>=0 ){
sqlite3WalEndWriteTransaction(pWal);
walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
pWal->readLock = -1;
}
}
/*
** Search the wal file for page pgno. If found, set *piRead to the frame that
|
| ︙ | ︙ | |||
68829 68830 68831 68832 68833 68834 68835 |
int rc;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* If the write-lock is already held, then it was obtained before the
** read-transaction was even opened, making this call a no-op.
** Return early. */
if( pWal->writeLock ){
| | | 69317 69318 69319 69320 69321 69322 69323 69324 69325 69326 69327 69328 69329 69330 69331 |
int rc;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* If the write-lock is already held, then it was obtained before the
** read-transaction was even opened, making this call a no-op.
** Return early. */
if( pWal->writeLock ){
assert( !memcmp(&pWal->hdr,(void*)pWal->apWiData[0],sizeof(WalIndexHdr)) );
return SQLITE_OK;
}
#endif
/* Cannot start a write transaction without first holding a read
** transaction. */
assert( pWal->readLock>=0 );
|
| ︙ | ︙ | |||
70278 70279 70280 70281 70282 70283 70284 70285 70286 70287 70288 70289 70290 70291 | ** root-node and 3 for all other internal nodes. ** ** If a tree that appears to be taller than this is encountered, it is ** assumed that the database is corrupt. */ #define BTCURSOR_MAX_DEPTH 20 /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. ** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. ** | > > > > > > | 70766 70767 70768 70769 70770 70771 70772 70773 70774 70775 70776 70777 70778 70779 70780 70781 70782 70783 70784 70785 | ** root-node and 3 for all other internal nodes. ** ** If a tree that appears to be taller than this is encountered, it is ** assumed that the database is corrupt. */ #define BTCURSOR_MAX_DEPTH 20 /* ** Maximum amount of storage local to a database page, regardless of ** page size. */ #define BT_MAX_LOCAL 65501 /* 65536 - 35 */ /* ** A cursor is a pointer to a particular entry within a particular ** b-tree within a database file. ** ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. ** |
| ︙ | ︙ | |||
70686 70687 70688 70689 70690 70691 70692 |
** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
*/
static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
int i;
| | | 71180 71181 71182 71183 71184 71185 71186 71187 71188 71189 71190 71191 71192 71193 71194 |
** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
*/
static void SQLITE_NOINLINE btreeEnterAll(sqlite3 *db){
int i;
u8 skipOk = 1;
Btree *p;
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb; i++){
p = db->aDb[i].pBt;
if( p && p->sharable ){
sqlite3BtreeEnter(p);
skipOk = 0;
|
| ︙ | ︙ | |||
71832 71833 71834 71835 71836 71837 71838 |
/*
** Provide flag hints to the cursor.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
| | | 72326 72327 72328 72329 72330 72331 72332 72333 72334 72335 72336 72337 72338 72339 72340 |
/*
** Provide flag hints to the cursor.
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHintFlags(BtCursor *pCur, unsigned x){
assert( x==BTREE_SEEK_EQ || x==BTREE_BULKLOAD || x==0 );
pCur->hints = (u8)x;
}
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Given a page number of a regular database page, return the page
** number for the pointer-map page that contains the entry for the
|
| ︙ | ︙ | |||
72026 72027 72028 72029 72030 72031 72032 72033 |
/*
** Given a record with nPayload bytes of payload stored within btree
** page pPage, return the number of bytes of payload stored locally.
*/
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
int maxLocal; /* Maximum amount of payload held locally */
maxLocal = pPage->maxLocal;
if( nPayload<=maxLocal ){
| > | | | | 72520 72521 72522 72523 72524 72525 72526 72527 72528 72529 72530 72531 72532 72533 72534 72535 72536 72537 72538 72539 72540 72541 72542 |
/*
** Given a record with nPayload bytes of payload stored within btree
** page pPage, return the number of bytes of payload stored locally.
*/
static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
int maxLocal; /* Maximum amount of payload held locally */
maxLocal = pPage->maxLocal;
assert( nPayload>=0 );
if( nPayload<=maxLocal ){
return (int)nPayload;
}else{
int minLocal; /* Minimum amount of payload held locally */
int surplus; /* Overflow payload available for local storage */
minLocal = pPage->minLocal;
surplus = (int)(minLocal +(nPayload - minLocal)%(pPage->pBt->usableSize-4));
return (surplus <= maxLocal) ? surplus : minLocal;
}
}
/*
** The following routines are implementations of the MemPage.xParseCell()
** method.
**
|
| ︙ | ︙ | |||
72143 72144 72145 72146 72147 72148 72149 72150 72151 72152 72153 |
pIter++;
pInfo->nKey = *(i64*)&iKey;
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
| > > | | 72638 72639 72640 72641 72642 72643 72644 72645 72646 72647 72648 72649 72650 72651 72652 72653 72654 72655 72656 72657 72658 |
pIter++;
pInfo->nKey = *(i64*)&iKey;
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
assert( nPayload>=0 );
assert( pPage->maxLocal <= BT_MAX_LOCAL );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
}else{
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
}
}
static void btreeParseCellPtrIndex(
|
| ︙ | ︙ | |||
72180 72181 72182 72183 72184 72185 72186 72187 72188 72189 72190 |
}
pIter++;
pInfo->nKey = nPayload;
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
| > > | | 72677 72678 72679 72680 72681 72682 72683 72684 72685 72686 72687 72688 72689 72690 72691 72692 72693 72694 72695 72696 72697 |
}
pIter++;
pInfo->nKey = nPayload;
pInfo->nPayload = nPayload;
pInfo->pPayload = pIter;
testcase( nPayload==pPage->maxLocal );
testcase( nPayload==(u32)pPage->maxLocal+1 );
assert( nPayload>=0 );
assert( pPage->maxLocal <= BT_MAX_LOCAL );
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
** on the local page. No overflow is required.
*/
pInfo->nSize = (u16)nPayload + (u16)(pIter - pCell);
if( pInfo->nSize<4 ) pInfo->nSize = 4;
pInfo->nLocal = (u16)nPayload;
}else{
btreeParseCellAdjustSizeForOverflow(pPage, pCell, pInfo);
}
}
static void btreeParseCell(
|
| ︙ | ︙ | |||
72723 72724 72725 72726 72727 72728 72729 | ** ** Even though the freeblock list was checked by btreeComputeFreeSpace(), ** that routine will not detect overlap between cells or freeblocks. Nor ** does it detect cells or freeblocks that encroach into the reserved bytes ** at the end of the page. So do additional corruption checks inside this ** routine and return SQLITE_CORRUPT if any problems are found. */ | | | | | | | | | 73222 73223 73224 73225 73226 73227 73228 73229 73230 73231 73232 73233 73234 73235 73236 73237 73238 73239 73240 73241 73242 73243 |
**
** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
** does it detect cells or freeblocks that encroach into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
static int freeSpace(MemPage *pPage, int iStart, int iSize){
int iPtr; /* Address of ptr to next freeblock */
int iFreeBlk; /* Address of the next freeblock */
u8 hdr; /* Page header size. 0 or 100 */
int nFrag = 0; /* Reduction in fragmentation */
int iOrigSize = iSize; /* Original value of iSize */
int x; /* Offset to cell content area */
int iEnd = iStart + iSize; /* First byte past the iStart buffer */
unsigned char *data = pPage->aData; /* Page content */
u8 *pTmp; /* Temporary ptr into data[] */
assert( pPage->pBt!=0 );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( CORRUPT_DB || iStart>=pPage->hdrOffset+6+pPage->childPtrSize );
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
|
| ︙ | ︙ | |||
72757 72758 72759 72760 72761 72762 72763 |
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
iPtr = iFreeBlk;
}
| | | | > | | 73256 73257 73258 73259 73260 73261 73262 73263 73264 73265 73266 73267 73268 73269 73270 73271 73272 73273 73274 73275 73276 73277 73278 73279 73280 73281 73282 73283 73284 73285 73286 73287 73288 73289 73290 73291 73292 73293 73294 73295 73296 73297 73298 73299 73300 73301 73302 73303 73304 73305 73306 73307 73308 73309 73310 73311 73312 73313 73314 73315 73316 73317 73318 73319 73320 73321 73322 73323 73324 73325 73326 73327 73328 |
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
if( iFreeBlk<=iPtr ){
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
iPtr = iFreeBlk;
}
if( iFreeBlk>(int)pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB );
/* At this point:
** iFreeBlk: First freeblock after iStart, or zero if none
** iPtr: The address of a pointer to iFreeBlk
**
** Check to see if iFreeBlk should be coalesced onto the end of iStart.
*/
if( iFreeBlk && iEnd+3>=iFreeBlk ){
nFrag = iFreeBlk - iEnd;
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
if( iEnd > (int)pPage->pBt->usableSize ){
return SQLITE_CORRUPT_PAGE(pPage);
}
iSize = iEnd - iStart;
iFreeBlk = get2byte(&data[iFreeBlk]);
}
/* If iPtr is another freeblock (that is, if iPtr is not the freelist
** pointer in the page header) then check to see if iStart should be
** coalesced onto the end of iPtr.
*/
if( iPtr>hdr+1 ){
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
if( iPtrEnd+3>=iStart ){
if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
nFrag += iStart - iPtrEnd;
iSize = iEnd - iPtr;
iStart = iPtr;
}
}
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
data[hdr+7] -= (u8)nFrag;
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
/* Overwrite deleted information with zeros when the secure_delete
** option is enabled */
memset(&data[iStart], 0, iSize);
}
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
** freelist entry */
if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage);
if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
put2byte(&data[hdr+1], iFreeBlk);
put2byte(&data[hdr+5], iEnd);
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
put2byte(&data[iStart], iFreeBlk);
assert( iSize>=0 && iSize<=0xffff );
put2byte(&data[iStart+2], (u16)iSize);
}
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
/*
** Decode the flags byte (the first byte of the header) for a page
|
| ︙ | ︙ | |||
73040 73041 73042 73043 73044 73045 73046 |
** the b-tree page type. */
if( decodeFlags(pPage, data[0]) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0;
| | | 73540 73541 73542 73543 73544 73545 73546 73547 73548 73549 73550 73551 73552 73553 73554 |
** the b-tree page type. */
if( decodeFlags(pPage, data[0]) ){
return SQLITE_CORRUPT_PAGE(pPage);
}
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nOverflow = 0;
pPage->cellOffset = (u16)(pPage->hdrOffset + 8 + pPage->childPtrSize);
pPage->aCellIdx = data + pPage->childPtrSize + 8;
pPage->aDataEnd = pPage->aData + pBt->pageSize;
pPage->aDataOfst = pPage->aData + pPage->childPtrSize;
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
** number of cells on the page. */
pPage->nCell = get2byte(&data[3]);
if( pPage->nCell>MX_CELL(pBt) ){
|
| ︙ | ︙ | |||
73074 73075 73076 73077 73078 73079 73080 |
/*
** Set up a raw page so that it looks like a database page holding
** no entries.
*/
static void zeroPage(MemPage *pPage, int flags){
unsigned char *data = pPage->aData;
BtShared *pBt = pPage->pBt;
| | | | | 73574 73575 73576 73577 73578 73579 73580 73581 73582 73583 73584 73585 73586 73587 73588 73589 73590 73591 73592 73593 73594 73595 73596 73597 73598 73599 73600 73601 73602 73603 73604 73605 73606 |
/*
** Set up a raw page so that it looks like a database page holding
** no entries.
*/
static void zeroPage(MemPage *pPage, int flags){
unsigned char *data = pPage->aData;
BtShared *pBt = pPage->pBt;
int hdr = pPage->hdrOffset;
int first;
assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB );
assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( sqlite3_mutex_held(pBt->mutex) );
if( pBt->btsFlags & BTS_FAST_SECURE ){
memset(&data[hdr], 0, pBt->usableSize - hdr);
}
data[hdr] = (char)flags;
first = hdr + ((flags&PTF_LEAF)==0 ? 12 : 8);
memset(&data[hdr+1], 0, 4);
data[hdr+7] = 0;
put2byte(&data[hdr+5], pBt->usableSize);
pPage->nFree = (u16)(pBt->usableSize - first);
decodeFlags(pPage, flags);
pPage->cellOffset = (u16)first;
pPage->aDataEnd = &data[pBt->pageSize];
pPage->aCellIdx = &data[first];
pPage->aDataOfst = &data[pPage->childPtrSize];
pPage->nOverflow = 0;
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
pPage->maskPage = (u16)(pBt->pageSize - 1);
pPage->nCell = 0;
|
| ︙ | ︙ | |||
73878 73879 73880 73881 73882 73883 73884 |
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
int rc = SQLITE_OK;
int x;
BtShared *pBt = p->pBt;
assert( nReserve>=0 && nReserve<=255 );
sqlite3BtreeEnter(p);
| | | 74378 74379 74380 74381 74382 74383 74384 74385 74386 74387 74388 74389 74390 74391 74392 |
*/
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
int rc = SQLITE_OK;
int x;
BtShared *pBt = p->pBt;
assert( nReserve>=0 && nReserve<=255 );
sqlite3BtreeEnter(p);
pBt->nReserveWanted = (u8)nReserve;
x = pBt->pageSize - pBt->usableSize;
if( nReserve<x ) nReserve = x;
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
sqlite3BtreeLeave(p);
return SQLITE_READONLY;
}
assert( nReserve>=0 && nReserve<=255 );
|
| ︙ | ︙ | |||
73984 73985 73986 73987 73988 73989 73990 |
int b;
if( p==0 ) return 0;
sqlite3BtreeEnter(p);
assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 );
assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
if( newFlag>=0 ){
p->pBt->btsFlags &= ~BTS_FAST_SECURE;
| | | 74484 74485 74486 74487 74488 74489 74490 74491 74492 74493 74494 74495 74496 74497 74498 |
int b;
if( p==0 ) return 0;
sqlite3BtreeEnter(p);
assert( BTS_OVERWRITE==BTS_SECURE_DELETE*2 );
assert( BTS_FAST_SECURE==(BTS_OVERWRITE|BTS_SECURE_DELETE) );
if( newFlag>=0 ){
p->pBt->btsFlags &= ~BTS_FAST_SECURE;
p->pBt->btsFlags |= (u16)(BTS_SECURE_DELETE*newFlag);
}
b = (p->pBt->btsFlags & BTS_FAST_SECURE)/BTS_SECURE_DELETE;
sqlite3BtreeLeave(p);
return b;
}
/*
|
| ︙ | ︙ | |||
78432 78433 78434 78435 78436 78437 78438 |
if( pCArray->ixNx[k]<=i ){
k++;
pSrcEnd = pCArray->apEnd[k];
}
}
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
| > | | 78932 78933 78934 78935 78936 78937 78938 78939 78940 78941 78942 78943 78944 78945 78946 78947 |
if( pCArray->ixNx[k]<=i ){
k++;
pSrcEnd = pCArray->apEnd[k];
}
}
/* The pPg->nFree field is now set incorrectly. The caller will fix it. */
assert( nCell < 10922 );
pPg->nCell = (u16)nCell;
pPg->nOverflow = 0;
put2byte(&aData[hdr+1], 0);
put2byte(&aData[hdr+3], pPg->nCell);
put2byte(&aData[hdr+5], pData - aData);
aData[hdr+7] = 0x00;
return SQLITE_OK;
|
| ︙ | ︙ | |||
78679 78680 78681 78682 78683 78684 78685 |
/* Append cells to the end of the page */
assert( nCell>=0 );
pCellptr = &pPg->aCellIdx[nCell*2];
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
iNew+nCell, nNew-nCell, pCArray
| > > | | > > | | 79180 79181 79182 79183 79184 79185 79186 79187 79188 79189 79190 79191 79192 79193 79194 79195 79196 79197 79198 79199 79200 |
/* Append cells to the end of the page */
assert( nCell>=0 );
pCellptr = &pPg->aCellIdx[nCell*2];
if( pageInsertArray(
pPg, pBegin, &pData, pCellptr,
iNew+nCell, nNew-nCell, pCArray
)
){
goto editpage_fail;
}
assert( nNew < 10922 );
pPg->nCell = (u16)nNew;
pPg->nOverflow = 0;
put2byte(&aData[hdr+3], pPg->nCell);
put2byte(&aData[hdr+5], pData - aData);
#ifdef SQLITE_DEBUG
for(i=0; i<nNew && !CORRUPT_DB; i++){
|
| ︙ | ︙ | |||
78990 78991 78992 78993 78994 78995 78996 | int rc = SQLITE_OK; /* The return code */ u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */ int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ int usableSpace; /* Bytes in pPage beyond the header */ int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ | | | 79495 79496 79497 79498 79499 79500 79501 79502 79503 79504 79505 79506 79507 79508 79509 | int rc = SQLITE_OK; /* The return code */ u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */ int leafData; /* True if pPage is a leaf of a LEAFDATA tree */ int usableSpace; /* Bytes in pPage beyond the header */ int pageFlags; /* Value of pPage->aData[0] */ int iSpace1 = 0; /* First unused byte of aSpace1[] */ int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */ u64 szScratch; /* Size of scratch memory requested */ MemPage *apOld[NB]; /* pPage and up to two siblings */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ u8 *pRight; /* Location in parent of right-sibling pointer */ u8 *apDiv[NB-1]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in b.paCell[] of cell after i-th page */ int cntOld[NB+2]; /* Old index in b.apCell[] */ int szNew[NB+2]; /* Combined size of cells placed on i-th page */ |
| ︙ | ︙ | |||
80275 80276 80277 80278 80279 80280 80281 |
** overwrite optimization.
*/
if( loc==0 ){
getCellInfo(pCur);
if( pCur->info.nKey==pX->nKey ){
BtreePayload x2;
x2.pData = pX->pKey;
| | | 80780 80781 80782 80783 80784 80785 80786 80787 80788 80789 80790 80791 80792 80793 80794 |
** overwrite optimization.
*/
if( loc==0 ){
getCellInfo(pCur);
if( pCur->info.nKey==pX->nKey ){
BtreePayload x2;
x2.pData = pX->pKey;
x2.nData = (int)pX->nKey; assert( pX->nKey<=0x7fffffff );
x2.nZero = 0;
return btreeOverwriteCell(pCur, &x2);
}
}
}
assert( pCur->eState==CURSOR_VALID
|| (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
|
| ︙ | ︙ | |||
80456 80457 80458 80459 80460 80461 80462 |
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
const u8 *aIn; /* Pointer to next input buffer */
u32 nIn; /* Size of input buffer aIn[] */
u32 nRem; /* Bytes of data still to copy */
getCellInfo(pSrc);
if( pSrc->info.nPayload<0x80 ){
| | | | | 80961 80962 80963 80964 80965 80966 80967 80968 80969 80970 80971 80972 80973 80974 80975 80976 80977 80978 80979 80980 80981 80982 80983 80984 80985 80986 80987 80988 80989 80990 80991 80992 80993 80994 80995 80996 80997 80998 80999 81000 |
u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
const u8 *aIn; /* Pointer to next input buffer */
u32 nIn; /* Size of input buffer aIn[] */
u32 nRem; /* Bytes of data still to copy */
getCellInfo(pSrc);
if( pSrc->info.nPayload<0x80 ){
*(aOut++) = (u8)pSrc->info.nPayload;
}else{
aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
}
if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
nIn = pSrc->info.nLocal;
aIn = pSrc->info.pPayload;
if( aIn+nIn>pSrc->pPage->aDataEnd ){
return SQLITE_CORRUPT_PAGE(pSrc->pPage);
}
nRem = pSrc->info.nPayload;
if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
memcpy(aOut, aIn, nIn);
pBt->nPreformatSize = nIn + (int)(aOut - pBt->pTmpSpace);
return SQLITE_OK;
}else{
int rc = SQLITE_OK;
Pager *pSrcPager = pSrc->pBt->pPager;
u8 *pPgnoOut = 0;
Pgno ovflIn = 0;
DbPage *pPageIn = 0;
MemPage *pPageOut = 0;
u32 nOut; /* Size of output buffer aOut[] */
nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
pBt->nPreformatSize = (int)nOut + (int)(aOut - pBt->pTmpSpace);
if( nOut<pSrc->info.nPayload ){
pPgnoOut = &aOut[nOut];
pBt->nPreformatSize += 4;
}
if( nRem>nIn ){
if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
|
| ︙ | ︙ | |||
85582 85583 85584 85585 85586 85587 85588 |
int p2, /* First argument register */
int p3, /* Register into which results are written */
int nArg, /* Number of argument */
const FuncDef *pFunc, /* The function to be invoked */
int eCallCtx /* Calling context */
){
Vdbe *v = pParse->pVdbe;
| < < | | 86087 86088 86089 86090 86091 86092 86093 86094 86095 86096 86097 86098 86099 86100 86101 86102 86103 86104 |
int p2, /* First argument register */
int p3, /* Register into which results are written */
int nArg, /* Number of argument */
const FuncDef *pFunc, /* The function to be invoked */
int eCallCtx /* Calling context */
){
Vdbe *v = pParse->pVdbe;
int addr;
sqlite3_context *pCtx;
assert( v );
pCtx = sqlite3DbMallocRawNN(pParse->db, SZ_CONTEXT(nArg));
if( pCtx==0 ){
assert( pParse->db->mallocFailed );
freeEphemeralFunction(pParse->db, (FuncDef*)pFunc);
return 0;
}
pCtx->pOut = 0;
pCtx->pFunc = (FuncDef*)pFunc;
|
| ︙ | ︙ | |||
90663 90664 90665 90666 90667 90668 90669 |
|| (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
preupdate.pCsr = pCsr;
preupdate.op = op;
preupdate.iNewReg = iReg;
| > | | | | | | | 91166 91167 91168 91169 91170 91171 91172 91173 91174 91175 91176 91177 91178 91179 91180 91181 91182 91183 91184 91185 91186 91187 91188 91189 91190 91191 91192 91193 91194 91195 |
|| (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
preupdate.pCsr = pCsr;
preupdate.op = op;
preupdate.iNewReg = iReg;
preupdate.pKeyinfo = (KeyInfo*)&preupdate.keyinfoSpace;
preupdate.pKeyinfo->db = db;
preupdate.pKeyinfo->enc = ENC(db);
preupdate.pKeyinfo->nKeyField = pTab->nCol;
preupdate.pKeyinfo->aSortFlags = (u8*)&fakeSortOrder;
preupdate.iKey1 = iKey1;
preupdate.iKey2 = iKey2;
preupdate.pTab = pTab;
preupdate.iBlobWrite = iBlobWrite;
db->pPreUpdate = &preupdate;
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
db->pPreUpdate = 0;
sqlite3DbFree(db, preupdate.aRecord);
vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pUnpacked);
vdbeFreeUnpacked(db, preupdate.pKeyinfo->nKeyField+1,preupdate.pNewUnpacked);
sqlite3VdbeMemRelease(&preupdate.oldipk);
if( preupdate.aNew ){
int i;
for(i=0; i<pCsr->nField; i++){
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
}
sqlite3DbNNFreeNN(db, preupdate.aNew);
|
| ︙ | ︙ | |||
92916 92917 92918 92919 92920 92921 92922 |
assert( p->pCsr->eCurType==CURTYPE_BTREE );
nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
aRec = sqlite3DbMallocRaw(db, nRec);
if( !aRec ) goto preupdate_old_out;
rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
if( rc==SQLITE_OK ){
| | | 93420 93421 93422 93423 93424 93425 93426 93427 93428 93429 93430 93431 93432 93433 93434 |
assert( p->pCsr->eCurType==CURTYPE_BTREE );
nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
aRec = sqlite3DbMallocRaw(db, nRec);
if( !aRec ) goto preupdate_old_out;
rc = sqlite3BtreePayload(p->pCsr->uc.pCursor, 0, nRec, aRec);
if( rc==SQLITE_OK ){
p->pUnpacked = vdbeUnpackRecord(p->pKeyinfo, nRec, aRec);
if( !p->pUnpacked ) rc = SQLITE_NOMEM;
}
if( rc!=SQLITE_OK ){
sqlite3DbFree(db, aRec);
goto preupdate_old_out;
}
p->aRecord = aRec;
|
| ︙ | ︙ | |||
92981 92982 92983 92984 92985 92986 92987 |
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p;
#ifdef SQLITE_ENABLE_API_ARMOR
p = db!=0 ? db->pPreUpdate : 0;
#else
p = db->pPreUpdate;
#endif
| | | 93485 93486 93487 93488 93489 93490 93491 93492 93493 93494 93495 93496 93497 93498 93499 |
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
PreUpdate *p;
#ifdef SQLITE_ENABLE_API_ARMOR
p = db!=0 ? db->pPreUpdate : 0;
#else
p = db->pPreUpdate;
#endif
return (p ? p->pKeyinfo->nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
** This function is designed to be called from within a pre-update callback
** only. It returns zero if the change that caused the callback was made
|
| ︙ | ︙ | |||
93064 93065 93066 93067 93068 93069 93070 |
/* For an INSERT, memory cell p->iNewReg contains the serialized record
** that is being inserted. Deserialize it. */
UnpackedRecord *pUnpack = p->pNewUnpacked;
if( !pUnpack ){
Mem *pData = &p->v->aMem[p->iNewReg];
rc = ExpandBlob(pData);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
| | | 93568 93569 93570 93571 93572 93573 93574 93575 93576 93577 93578 93579 93580 93581 93582 |
/* For an INSERT, memory cell p->iNewReg contains the serialized record
** that is being inserted. Deserialize it. */
UnpackedRecord *pUnpack = p->pNewUnpacked;
if( !pUnpack ){
Mem *pData = &p->v->aMem[p->iNewReg];
rc = ExpandBlob(pData);
if( rc!=SQLITE_OK ) goto preupdate_new_out;
pUnpack = vdbeUnpackRecord(p->pKeyinfo, pData->n, pData->z);
if( !pUnpack ){
rc = SQLITE_NOMEM;
goto preupdate_new_out;
}
p->pNewUnpacked = pUnpack;
}
pMem = &pUnpack->aMem[iStore];
|
| ︙ | ︙ | |||
93858 93859 93860 93861 93862 93863 93864 | ** the top of the register space. Cursor 1 is at Mem[p->nMem-1]. ** Cursor 2 is at Mem[p->nMem-2]. And so forth. */ Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem; i64 nByte; VdbeCursor *pCx = 0; | | | | | 94362 94363 94364 94365 94366 94367 94368 94369 94370 94371 94372 94373 94374 94375 94376 94377 94378 |
** the top of the register space. Cursor 1 is at Mem[p->nMem-1].
** Cursor 2 is at Mem[p->nMem-2]. And so forth.
*/
Mem *pMem = iCur>0 ? &p->aMem[p->nMem-iCur] : p->aMem;
i64 nByte;
VdbeCursor *pCx = 0;
nByte = SZ_VDBECURSOR(nField);
assert( ROUND8(nByte)==nByte );
if( eCurType==CURTYPE_BTREE ) nByte += sqlite3BtreeCursorSize();
assert( iCur>=0 && iCur<p->nCursor );
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
sqlite3VdbeFreeCursorNN(p, p->apCsr[iCur]);
p->apCsr[iCur] = 0;
}
|
| ︙ | ︙ | |||
93893 93894 93895 93896 93897 93898 93899 |
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
pCx->eCurType = eCurType;
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
| > | < | 94397 94398 94399 94400 94401 94402 94403 94404 94405 94406 94407 94408 94409 94410 94411 94412 |
p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
pCx->eCurType = eCurType;
pCx->nField = nField;
pCx->aOffset = &pCx->aType[nField];
if( eCurType==CURTYPE_BTREE ){
assert( ROUND8(SZ_VDBECURSOR(nField))==SZ_VDBECURSOR(nField) );
pCx->uc.pCursor = (BtCursor*)&pMem->z[SZ_VDBECURSOR(nField)];
sqlite3BtreeCursorZero(pCx->uc.pCursor);
}
return pCx;
}
/*
** The string in pRec is known to look like an integer and to have a
|
| ︙ | ︙ | |||
99636 99637 99638 99639 99640 99641 99642 | assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. | | | 100140 100141 100142 100143 100144 100145 100146 100147 100148 100149 100150 100151 100152 100153 100154 | assert( pC->nullRow==0 ); assert( pC->uc.pCursor!=0 ); pCrsr = pC->uc.pCursor; /* The OP_RowData opcodes always follow OP_NotExists or ** OP_SeekRowid or OP_Rewind/Op_Next with no intervening instructions ** that might invalidate the cursor. ** If this were not the case, one of the following assert()s ** would fail. Should this ever change (because of changes in the code ** generator) then the fix would be to insert a call to ** sqlite3VdbeCursorMoveto(). */ assert( pC->deferredMoveto==0 ); assert( sqlite3BtreeCursorIsValid(pCrsr) ); |
| ︙ | ︙ | |||
101285 101286 101287 101288 101289 101290 101291 | /* Allocate space for (a) the context object and (n-1) extra pointers ** to append to the sqlite3_context.argv[1] array, and (b) a memory ** cell in which to store the accumulation. Be careful that the memory ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits. ** ** Note: We could avoid this by using a regular memory cell from aMem[] for ** the accumulator, instead of allocating one here. */ | | | 101789 101790 101791 101792 101793 101794 101795 101796 101797 101798 101799 101800 101801 101802 101803 | /* Allocate space for (a) the context object and (n-1) extra pointers ** to append to the sqlite3_context.argv[1] array, and (b) a memory ** cell in which to store the accumulation. Be careful that the memory ** cell is 8-byte aligned, even on platforms where a pointer is 32-bits. ** ** Note: We could avoid this by using a regular memory cell from aMem[] for ** the accumulator, instead of allocating one here. */ nAlloc = ROUND8P( SZ_CONTEXT(n) ); pCtx = sqlite3DbMallocRawNN(db, nAlloc + sizeof(Mem)); if( pCtx==0 ) goto no_mem; pCtx->pOut = (Mem*)((u8*)pCtx + nAlloc); assert( EIGHT_BYTE_ALIGNMENT(pCtx->pOut) ); sqlite3VdbeMemInit(pCtx->pOut, db, MEM_Null); pCtx->pMem = 0; |
| ︙ | ︙ | |||
102943 102944 102945 102946 102947 102948 102949 102950 102951 102952 102953 102954 102955 102956 |
){
int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
Incrblob *pBlob = 0;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
| > | 103447 103448 103449 103450 103451 103452 103453 103454 103455 103456 103457 103458 103459 103460 103461 |
){
int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
Incrblob *pBlob = 0;
int iDb;
Parse sParse;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppBlob==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
|
| ︙ | ︙ | |||
102988 102989 102990 102991 102992 102993 102994 |
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && IsView(pTab) ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
| | > > > | | 103493 103494 103495 103496 103497 103498 103499 103500 103501 103502 103503 103504 103505 103506 103507 103508 103509 103510 103511 103512 103513 103514 103515 103516 103517 103518 103519 103520 103521 |
}
#ifndef SQLITE_OMIT_VIEW
if( pTab && IsView(pTab) ){
pTab = 0;
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
}
#endif
if( pTab==0
|| ((iDb = sqlite3SchemaToIndex(db, pTab->pSchema))==1 &&
sqlite3OpenTempDatabase(&sParse))
){
if( sParse.zErrMsg ){
sqlite3DbFree(db, zErr);
zErr = sParse.zErrMsg;
sParse.zErrMsg = 0;
}
rc = SQLITE_ERROR;
sqlite3BtreeLeaveAll(db);
goto blob_open_out;
}
pBlob->pTab = pTab;
pBlob->zDb = db->aDb[iDb].zDbSName;
/* Now search pTab for the exact column. */
iCol = sqlite3ColumnIndex(pTab, zColumn);
if( iCol<0 ){
sqlite3DbFree(db, zErr);
zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
rc = SQLITE_ERROR;
|
| ︙ | ︙ | |||
103083 103084 103085 103086 103087 103088 103089 |
/* blobSeekToRow() will initialize r[1] to the desired rowid */
{OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */
{OP_Column, 0, 0, 1}, /* 3 */
{OP_ResultRow, 1, 0, 0}, /* 4 */
{OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
| < | 103591 103592 103593 103594 103595 103596 103597 103598 103599 103600 103601 103602 103603 103604 |
/* blobSeekToRow() will initialize r[1] to the desired rowid */
{OP_NotExists, 0, 5, 1}, /* 2: Seek the cursor to rowid=r[1] */
{OP_Column, 0, 0, 1}, /* 3 */
{OP_ResultRow, 1, 0, 0}, /* 4 */
{OP_Halt, 0, 0, 0}, /* 5 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
VdbeOp *aOp;
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
assert( sqlite3VdbeCurrentAddr(v)==2 || db->mallocFailed );
|
| ︙ | ︙ | |||
103661 103662 103663 103664 103665 103666 103667 | int iMemory; /* Offset of free space in list.aMemory */ int nMemory; /* Size of list.aMemory allocation in bytes */ u8 bUsePMA; /* True if one or more PMAs created */ u8 bUseThreads; /* True to use background threads */ u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ u8 typeMask; | | > > > | 104168 104169 104170 104171 104172 104173 104174 104175 104176 104177 104178 104179 104180 104181 104182 104183 104184 104185 104186 | int iMemory; /* Offset of free space in list.aMemory */ int nMemory; /* Size of list.aMemory allocation in bytes */ u8 bUsePMA; /* True if one or more PMAs created */ u8 bUseThreads; /* True to use background threads */ u8 iPrev; /* Previous thread used to flush PMA */ u8 nTask; /* Size of aTask[] array */ u8 typeMask; SortSubtask aTask[FLEXARRAY]; /* One or more subtasks */ }; /* Size (in bytes) of a VdbeSorter object that works with N or fewer subtasks */ #define SZ_VDBESORTER(N) (offsetof(VdbeSorter,aTask)+(N)*sizeof(SortSubtask)) #define SORTER_TYPE_INTEGER 0x01 #define SORTER_TYPE_TEXT 0x02 /* ** An instance of the following object is used to read records out of a ** PMA, in sorted order. The next key to be read is cached in nKey/aKey. |
| ︙ | ︙ | |||
104295 104296 104297 104298 104299 104300 104301 |
#endif
assert( pCsr->pKeyInfo );
assert( !pCsr->isEphemeral );
assert( pCsr->eCurType==CURTYPE_SORTER );
assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
< 0x7fffffff );
| | | | 104805 104806 104807 104808 104809 104810 104811 104812 104813 104814 104815 104816 104817 104818 104819 104820 |
#endif
assert( pCsr->pKeyInfo );
assert( !pCsr->isEphemeral );
assert( pCsr->eCurType==CURTYPE_SORTER );
assert( sizeof(KeyInfo) + UMXV(pCsr->pKeyInfo->nKeyField)*sizeof(CollSeq*)
< 0x7fffffff );
szKeyInfo = SZ_KEYINFO(pCsr->pKeyInfo->nKeyField+1);
sz = SZ_VDBESORTER(nWorker+1);
pSorter = (VdbeSorter*)sqlite3DbMallocZero(db, sz + szKeyInfo);
pCsr->uc.pSorter = pSorter;
if( pSorter==0 ){
rc = SQLITE_NOMEM_BKPT;
}else{
Btree *pBt = db->aDb[0].pBt;
|
| ︙ | ︙ | |||
104760 104761 104762 104763 104764 104765 104766 104767 104768 104769 104770 104771 104772 104773 |
}else{
pNext = p->u.pNext;
}
p->u.pNext = 0;
for(i=0; aSlot[i]; i++){
p = vdbeSorterMerge(pTask, p, aSlot[i]);
aSlot[i] = 0;
}
aSlot[i] = p;
p = pNext;
}
p = 0;
| > > > > | 105270 105271 105272 105273 105274 105275 105276 105277 105278 105279 105280 105281 105282 105283 105284 105285 105286 105287 |
}else{
pNext = p->u.pNext;
}
p->u.pNext = 0;
for(i=0; aSlot[i]; i++){
p = vdbeSorterMerge(pTask, p, aSlot[i]);
/* ,--Each aSlot[] holds twice as much as the previous. So we cannot use
** | up all 64 aSlots[] with only a 64-bit address space.
** v */
assert( i<ArraySize(aSlot) );
aSlot[i] = 0;
}
aSlot[i] = p;
p = pNext;
}
p = 0;
|
| ︙ | ︙ | |||
109534 109535 109536 109537 109538 109539 109540 |
SQLITE_PRIVATE int sqlite3ResolveSelfReference(
Parse *pParse, /* Parsing context */
Table *pTab, /* The table being referenced, or NULL */
int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NULL. */
){
| | > > | | | | | | | 110048 110049 110050 110051 110052 110053 110054 110055 110056 110057 110058 110059 110060 110061 110062 110063 110064 110065 110066 110067 110068 110069 110070 110071 110072 110073 110074 110075 110076 110077 110078 110079 110080 110081 110082 110083 110084 110085 |
SQLITE_PRIVATE int sqlite3ResolveSelfReference(
Parse *pParse, /* Parsing context */
Table *pTab, /* The table being referenced, or NULL */
int type, /* NC_IsCheck, NC_PartIdx, NC_IdxExpr, NC_GenCol, or 0 */
Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NULL. */
){
SrcList *pSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context for pParse->pNewTable */
int rc;
u8 srcSpace[SZ_SRCLIST_1]; /* Memory space for the fake SrcList */
assert( type==0 || pTab!=0 );
assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr
|| type==NC_GenCol || pTab==0 );
memset(&sNC, 0, sizeof(sNC));
pSrc = (SrcList*)srcSpace;
memset(pSrc, 0, SZ_SRCLIST_1);
if( pTab ){
pSrc->nSrc = 1;
pSrc->a[0].zName = pTab->zName;
pSrc->a[0].pSTab = pTab;
pSrc->a[0].iCursor = -1;
if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){
/* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP
** schema elements */
type |= NC_FromDDL;
}
}
sNC.pParse = pParse;
sNC.pSrcList = pSrc;
sNC.ncFlags = type | NC_IsDDL;
if( (rc = sqlite3ResolveExprNames(&sNC, pExpr))!=SQLITE_OK ) return rc;
if( pList ) rc = sqlite3ResolveExprListNames(&sNC, pList);
return rc;
}
/************** End of resolve.c *********************************************/
|
| ︙ | ︙ | |||
111304 111305 111306 111307 111308 111309 111310 |
** argument. If an OOM condition is encountered, NULL is returned
** and the db->mallocFailed flag set.
*/
#ifndef SQLITE_OMIT_CTE
SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
With *pRet = 0;
if( p ){
| | | 111820 111821 111822 111823 111824 111825 111826 111827 111828 111829 111830 111831 111832 111833 111834 |
** argument. If an OOM condition is encountered, NULL is returned
** and the db->mallocFailed flag set.
*/
#ifndef SQLITE_OMIT_CTE
SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
With *pRet = 0;
if( p ){
sqlite3_int64 nByte = SZ_WITH(p->nCte);
pRet = sqlite3DbMallocZero(db, nByte);
if( pRet ){
int i;
pRet->nCte = p->nCte;
for(i=0; i<p->nCte; i++){
pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0);
pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0);
|
| ︙ | ︙ | |||
111431 111432 111433 111434 111435 111436 111437 |
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
SrcList *pNew;
int i;
| < < | | 111947 111948 111949 111950 111951 111952 111953 111954 111955 111956 111957 111958 111959 111960 111961 111962 111963 |
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
SrcList *pNew;
int i;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, SZ_SRCLIST(p->nSrc) );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
SrcItem *pNewItem = &pNew->a[i];
const SrcItem *pOldItem = &p->a[i];
Table *pTab;
pNewItem->fg = pOldItem->fg;
|
| ︙ | ︙ | |||
111497 111498 111499 111500 111501 111502 111503 |
return pNew;
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
IdList *pNew;
int i;
assert( db!=0 );
if( p==0 ) return 0;
| | | 112011 112012 112013 112014 112015 112016 112017 112018 112019 112020 112021 112022 112023 112024 112025 |
return pNew;
}
SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
IdList *pNew;
int i;
assert( db!=0 );
if( p==0 ) return 0;
pNew = sqlite3DbMallocRawNN(db, SZ_IDLIST(p->nId));
if( pNew==0 ) return 0;
pNew->nId = p->nId;
for(i=0; i<p->nId; i++){
struct IdList_item *pNewItem = &pNew->a[i];
const struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
}
|
| ︙ | ︙ | |||
111529 111530 111531 111532 111533 111534 111535 |
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
pNew->pNext = pNext;
pNew->pPrior = 0;
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
| | | 112043 112044 112045 112046 112047 112048 112049 112050 112051 112052 112053 112054 112055 112056 112057 |
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, flags);
pNew->op = p->op;
pNew->pNext = pNext;
pNew->pPrior = 0;
pNew->pLimit = sqlite3ExprDup(db, p->pLimit, flags);
pNew->iLimit = 0;
pNew->iOffset = 0;
pNew->selFlags = p->selFlags & ~(u32)SF_UsesEphemeral;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = p->nSelectRow;
pNew->pWith = sqlite3WithDup(db, p->pWith);
#ifndef SQLITE_OMIT_WINDOWFUNC
pNew->pWin = 0;
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
|
| ︙ | ︙ | |||
111581 111582 111583 111584 111585 111586 111587 |
SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew(
sqlite3 *db, /* Database handle. Used for memory allocation */
Expr *pExpr /* Expression to be appended. Might be NULL */
){
struct ExprList_item *pItem;
ExprList *pList;
| | | < | 112095 112096 112097 112098 112099 112100 112101 112102 112103 112104 112105 112106 112107 112108 112109 112110 112111 112112 112113 112114 112115 112116 112117 112118 112119 112120 112121 112122 112123 112124 112125 112126 112127 112128 112129 |
SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew(
sqlite3 *db, /* Database handle. Used for memory allocation */
Expr *pExpr /* Expression to be appended. Might be NULL */
){
struct ExprList_item *pItem;
ExprList *pList;
pList = sqlite3DbMallocRawNN(db, SZ_EXPRLIST(4));
if( pList==0 ){
sqlite3ExprDelete(db, pExpr);
return 0;
}
pList->nAlloc = 4;
pList->nExpr = 1;
pItem = &pList->a[0];
*pItem = zeroItem;
pItem->pExpr = pExpr;
return pList;
}
SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow(
sqlite3 *db, /* Database handle. Used for memory allocation */
ExprList *pList, /* List to which to append. Might be NULL */
Expr *pExpr /* Expression to be appended. Might be NULL */
){
struct ExprList_item *pItem;
ExprList *pNew;
pList->nAlloc *= 2;
pNew = sqlite3DbRealloc(db, pList, SZ_EXPRLIST(pList->nAlloc));
if( pNew==0 ){
sqlite3ExprListDelete(db, pList);
sqlite3ExprDelete(db, pExpr);
return 0;
}else{
pList = pNew;
}
|
| ︙ | ︙ | |||
114238 114239 114240 114241 114242 114243 114244 |
return target;
}
return -1; /* Not found */
}
/*
| | | 114751 114752 114753 114754 114755 114756 114757 114758 114759 114760 114761 114762 114763 114764 114765 |
return target;
}
return -1; /* Not found */
}
/*
** Expression pExpr is guaranteed to be a TK_COLUMN or equivalent. This
** function checks the Parse.pIdxPartExpr list to see if this column
** can be replaced with a constant value. If so, it generates code to
** put the constant value in a register (ideally, but not necessarily,
** register iTarget) and returns the register number.
**
** Or, if the TK_COLUMN cannot be replaced by a constant, zero is
** returned.
|
| ︙ | ︙ | |||
117479 117480 117481 117482 117483 117484 117485 | if( !pNew ) goto exit_begin_add_column; pParse->pNewTable = pNew; pNew->nTabRef = 1; pNew->nCol = pTab->nCol; assert( pNew->nCol>0 ); nAlloc = (((pNew->nCol-1)/8)*8)+8; assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 ); | | | | 117992 117993 117994 117995 117996 117997 117998 117999 118000 118001 118002 118003 118004 118005 118006 118007 118008 118009 118010 118011 118012 |
if( !pNew ) goto exit_begin_add_column;
pParse->pNewTable = pNew;
pNew->nTabRef = 1;
pNew->nCol = pTab->nCol;
assert( pNew->nCol>0 );
nAlloc = (((pNew->nCol-1)/8)*8)+8;
assert( nAlloc>=pNew->nCol && nAlloc%8==0 && nAlloc-pNew->nCol<8 );
pNew->aCol = (Column*)sqlite3DbMallocZero(db, sizeof(Column)*(u32)nAlloc);
pNew->zName = sqlite3MPrintf(db, "sqlite_altertab_%s", pTab->zName);
if( !pNew->aCol || !pNew->zName ){
assert( db->mallocFailed );
goto exit_begin_add_column;
}
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*(size_t)pNew->nCol);
for(i=0; i<pNew->nCol; i++){
Column *pCol = &pNew->aCol[i];
pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName);
pCol->hName = sqlite3StrIHash(pCol->zCnName);
}
assert( IsOrdinaryTable(pNew) );
pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
|
| ︙ | ︙ | |||
118084 118085 118086 118087 118088 118089 118090 118091 118092 118093 118094 118095 118096 118097 118098 |
Parse *p, /* Memory to use for Parse object */
const char *zDb, /* Name of schema SQL belongs to */
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL to parse */
int bTemp /* True if SQL is from temp schema */
){
int rc;
sqlite3ParseObjectInit(p, db);
if( zSql==0 ){
return SQLITE_NOMEM;
}
if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){
return SQLITE_CORRUPT_BKPT;
}
| > > | > > > > > > > > > | 118597 118598 118599 118600 118601 118602 118603 118604 118605 118606 118607 118608 118609 118610 118611 118612 118613 118614 118615 118616 118617 118618 118619 118620 118621 118622 118623 118624 118625 118626 118627 118628 118629 118630 118631 118632 118633 118634 |
Parse *p, /* Memory to use for Parse object */
const char *zDb, /* Name of schema SQL belongs to */
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL to parse */
int bTemp /* True if SQL is from temp schema */
){
int rc;
u64 flags;
sqlite3ParseObjectInit(p, db);
if( zSql==0 ){
return SQLITE_NOMEM;
}
if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){
return SQLITE_CORRUPT_BKPT;
}
if( bTemp ){
db->init.iDb = 1;
}else{
int iDb = sqlite3FindDbName(db, zDb);
assert( iDb>=0 && iDb<=0xff );
db->init.iDb = (u8)iDb;
}
p->eParseMode = PARSE_MODE_RENAME;
p->db = db;
p->nQueryLoop = 1;
flags = db->flags;
testcase( (db->flags & SQLITE_Comments)==0 && strstr(zSql," /* ")!=0 );
db->flags |= SQLITE_Comments;
rc = sqlite3RunParser(p, zSql);
db->flags = flags;
if( db->mallocFailed ) rc = SQLITE_NOMEM;
if( rc==SQLITE_OK
&& NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0)
){
rc = SQLITE_CORRUPT_BKPT;
}
|
| ︙ | ︙ | |||
118159 118160 118161 118162 118163 118164 118165 |
zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew);
if( zQuot==0 ){
return SQLITE_NOMEM;
}else{
nQuot = sqlite3Strlen30(zQuot)-1;
}
| | | > | | > | | | > | | | 118683 118684 118685 118686 118687 118688 118689 118690 118691 118692 118693 118694 118695 118696 118697 118698 118699 118700 118701 118702 118703 118704 118705 118706 118707 118708 118709 118710 118711 118712 118713 118714 118715 118716 118717 118718 118719 118720 118721 118722 118723 118724 118725 118726 118727 118728 118729 118730 118731 118732 118733 118734 118735 118736 118737 118738 118739 118740 118741 118742 118743 118744 118745 118746 118747 118748 118749 |
zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew);
if( zQuot==0 ){
return SQLITE_NOMEM;
}else{
nQuot = sqlite3Strlen30(zQuot)-1;
}
assert( nQuot>=nNew && nSql>=0 && nNew>=0 );
zOut = sqlite3DbMallocZero(db, (u64)(nSql + pRename->nList*nQuot + 1));
}else{
assert( nSql>0 );
zOut = (char*)sqlite3DbMallocZero(db, (u64)(nSql*2+1) * 3);
if( zOut ){
zBuf1 = &zOut[nSql*2+1];
zBuf2 = &zOut[nSql*4+2];
}
}
/* At this point pRename->pList contains a list of RenameToken objects
** corresponding to all tokens in the input SQL that must be replaced
** with the new column name, or with single-quoted versions of themselves.
** All that remains is to construct and return the edited SQL string. */
if( zOut ){
i64 nOut = nSql;
assert( nSql>0 );
memcpy(zOut, zSql, (size_t)nSql);
while( pRename->pList ){
int iOff; /* Offset of token to replace in zOut */
i64 nReplace;
const char *zReplace;
RenameToken *pBest = renameColumnTokenNext(pRename);
if( zNew ){
if( bQuote==0 && sqlite3IsIdChar(*(u8*)pBest->t.z) ){
nReplace = nNew;
zReplace = zNew;
}else{
nReplace = nQuot;
zReplace = zQuot;
if( pBest->t.z[pBest->t.n]=='"' ) nReplace++;
}
}else{
/* Dequote the double-quoted token. Then requote it again, this time
** using single quotes. If the character immediately following the
** original token within the input SQL was a single quote ('), then
** add another space after the new, single-quoted version of the
** token. This is so that (SELECT "string"'alias') maps to
** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */
memcpy(zBuf1, pBest->t.z, pBest->t.n);
zBuf1[pBest->t.n] = 0;
sqlite3Dequote(zBuf1);
assert( nSql < 0x15555554 /* otherwise malloc would have failed */ );
sqlite3_snprintf((int)(nSql*2), zBuf2, "%Q%s", zBuf1,
pBest->t.z[pBest->t.n]=='\'' ? " " : ""
);
zReplace = zBuf2;
nReplace = sqlite3Strlen30(zReplace);
}
iOff = (int)(pBest->t.z - zSql);
if( pBest->t.n!=nReplace ){
memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
nOut - (iOff + pBest->t.n)
);
nOut += nReplace - pBest->t.n;
zOut[nOut] = '\0';
}
|
| ︙ | ︙ | |||
118234 118235 118236 118237 118238 118239 118240 118241 118242 118243 118244 |
return rc;
}
/*
** Set all pEList->a[].fg.eEName fields in the expression-list to val.
*/
static void renameSetENames(ExprList *pEList, int val){
if( pEList ){
int i;
for(i=0; i<pEList->nExpr; i++){
assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
| > | | 118761 118762 118763 118764 118765 118766 118767 118768 118769 118770 118771 118772 118773 118774 118775 118776 118777 118778 118779 118780 |
return rc;
}
/*
** Set all pEList->a[].fg.eEName fields in the expression-list to val.
*/
static void renameSetENames(ExprList *pEList, int val){
assert( val==ENAME_NAME || val==ENAME_TAB || val==ENAME_SPAN );
if( pEList ){
int i;
for(i=0; i<pEList->nExpr; i++){
assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
pEList->a[i].fg.eEName = val&0x3;
}
}
}
/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
|
| ︙ | ︙ | |||
118495 118496 118497 118498 118499 118500 118501 |
sWalker.u.pRename = &sCtx;
sCtx.pTab = pTab;
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
| | | 119023 119024 119025 119026 119027 119028 119029 119030 119031 119032 119033 119034 119035 119036 119037 |
sWalker.u.pRename = &sCtx;
sCtx.pTab = pTab;
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
pSelect->selFlags &= ~(u32)SF_View;
sParse.rc = SQLITE_OK;
sqlite3SelectPrep(&sParse, pSelect, 0);
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
if( rc==SQLITE_OK ){
sqlite3WalkSelect(&sWalker, pSelect);
}
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
| ︙ | ︙ | |||
118713 118714 118715 118716 118717 118718 118719 |
if( isLegacy==0 ){
Select *pSelect = pTab->u.view.pSelect;
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = &sParse;
assert( pSelect->selFlags & SF_View );
| | | 119241 119242 119243 119244 119245 119246 119247 119248 119249 119250 119251 119252 119253 119254 119255 |
if( isLegacy==0 ){
Select *pSelect = pTab->u.view.pSelect;
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = &sParse;
assert( pSelect->selFlags & SF_View );
pSelect->selFlags &= ~(u32)SF_View;
sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC);
if( sParse.nErr ){
rc = sParse.rc;
}else{
sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect);
}
}
|
| ︙ | ︙ | |||
118886 118887 118888 118889 118890 118891 118892 |
sWalker.xExprCallback = renameQuotefixExprCb;
sWalker.xSelectCallback = renameColumnSelectCb;
sWalker.u.pRename = &sCtx;
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
| | | 119414 119415 119416 119417 119418 119419 119420 119421 119422 119423 119424 119425 119426 119427 119428 |
sWalker.xExprCallback = renameQuotefixExprCb;
sWalker.xSelectCallback = renameColumnSelectCb;
sWalker.u.pRename = &sCtx;
if( sParse.pNewTable ){
if( IsView(sParse.pNewTable) ){
Select *pSelect = sParse.pNewTable->u.view.pSelect;
pSelect->selFlags &= ~(u32)SF_View;
sParse.rc = SQLITE_OK;
sqlite3SelectPrep(&sParse, pSelect, 0);
rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
if( rc==SQLITE_OK ){
sqlite3WalkSelect(&sWalker, pSelect);
}
}else{
|
| ︙ | ︙ | |||
118985 118986 118987 118988 118989 118990 118991 |
#endif
UNUSED_PARAMETER(NotUsed);
if( zDb && zInput ){
int rc;
Parse sParse;
| | | | 119513 119514 119515 119516 119517 119518 119519 119520 119521 119522 119523 119524 119525 119526 119527 119528 119529 119530 |
#endif
UNUSED_PARAMETER(NotUsed);
if( zDb && zInput ){
int rc;
Parse sParse;
u64 flags = db->flags;
if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL);
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
db->flags = flags;
if( rc==SQLITE_OK ){
if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = &sParse;
sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC);
if( sParse.nErr ) rc = sParse.rc;
|
| ︙ | ︙ | |||
119708 119709 119710 119711 119712 119713 119714 |
sqlite3_result_error_nomem(context);
return;
}
p->db = db;
p->nEst = sqlite3_value_int64(argv[2]);
p->nRow = 0;
| | | 120236 120237 120238 120239 120240 120241 120242 120243 120244 120245 120246 120247 120248 120249 120250 |
sqlite3_result_error_nomem(context);
return;
}
p->db = db;
p->nEst = sqlite3_value_int64(argv[2]);
p->nRow = 0;
p->nLimit = sqlite3_value_int(argv[3]);
p->nCol = nCol;
p->nKeyCol = nKeyCol;
p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
#ifdef SQLITE_ENABLE_STAT4
p->current.anEq = &p->current.anDLt[nColUp];
|
| ︙ | ︙ | |||
121517 121518 121519 121520 121521 121522 121523 121524 121525 121526 121527 121528 121529 121530 |
** remove the entry from the db->aDb[] array. i.e. put everything back the
** way we found it.
*/
if( rc==SQLITE_OK ){
sqlite3BtreeEnterAll(db);
db->init.iDb = 0;
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
if( !REOPEN_AS_MEMDB(db) ){
rc = sqlite3Init(db, &zErrDyn);
}
sqlite3BtreeLeaveAll(db);
assert( zErrDyn==0 || rc!=SQLITE_OK );
}
if( rc ){
| > > > > > > > | 122045 122046 122047 122048 122049 122050 122051 122052 122053 122054 122055 122056 122057 122058 122059 122060 122061 122062 122063 122064 122065 |
** remove the entry from the db->aDb[] array. i.e. put everything back the
** way we found it.
*/
if( rc==SQLITE_OK ){
sqlite3BtreeEnterAll(db);
db->init.iDb = 0;
db->mDbFlags &= ~(DBFLAG_SchemaKnownOk);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( db->setlkFlags & SQLITE_SETLK_BLOCK_ON_CONNECT ){
int val = 1;
sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pNew->pBt));
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, &val);
}
#endif
if( !REOPEN_AS_MEMDB(db) ){
rc = sqlite3Init(db, &zErrDyn);
}
sqlite3BtreeLeaveAll(db);
assert( zErrDyn==0 || rc!=SQLITE_OK );
}
if( rc ){
|
| ︙ | ︙ | |||
123238 123239 123240 123241 123242 123243 123244 | /* ** Convert an table column number into a index column number. That is, ** for the column iCol in the table (as defined by the CREATE TABLE statement) ** find the (first) offset of that column in index pIdx. Or return -1 ** if column iCol is not used in index pIdx. */ | | > > > > | > > | 123773 123774 123775 123776 123777 123778 123779 123780 123781 123782 123783 123784 123785 123786 123787 123788 123789 123790 123791 123792 123793 123794 123795 123796 |
/*
** Convert an table column number into a index column number. That is,
** for the column iCol in the table (as defined by the CREATE TABLE statement)
** find the (first) offset of that column in index pIdx. Or return -1
** if column iCol is not used in index pIdx.
*/
SQLITE_PRIVATE int sqlite3TableColumnToIndex(Index *pIdx, int iCol){
int i;
i16 iCol16;
assert( iCol>=(-1) && iCol<=SQLITE_MAX_COLUMN );
assert( pIdx->nColumn<=SQLITE_MAX_COLUMN );
iCol16 = iCol;
for(i=0; i<pIdx->nColumn; i++){
if( iCol16==pIdx->aiColumn[i] ){
return i;
}
}
return -1;
}
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
/* Convert a storage column number into a table column number.
**
|
| ︙ | ︙ | |||
124338 124339 124340 124341 124342 124343 124344 | return zStmt; } /* ** Resize an Index object to hold N columns total. Return SQLITE_OK ** on success and SQLITE_NOMEM on an OOM error. */ | | | > > > > > | | | 124879 124880 124881 124882 124883 124884 124885 124886 124887 124888 124889 124890 124891 124892 124893 124894 124895 124896 124897 124898 124899 124900 124901 124902 124903 124904 124905 124906 124907 124908 124909 124910 124911 124912 124913 124914 124915 124916 124917 |
return zStmt;
}
/*
** Resize an Index object to hold N columns total. Return SQLITE_OK
** on success and SQLITE_NOMEM on an OOM error.
*/
static int resizeIndexObject(Parse *pParse, Index *pIdx, int N){
char *zExtra;
u64 nByte;
sqlite3 *db;
if( pIdx->nColumn>=N ) return SQLITE_OK;
db = pParse->db;
assert( N>0 );
assert( N <= SQLITE_MAX_COLUMN*2 /* tag-20250221-1 */ );
testcase( N==2*pParse->db->aLimit[SQLITE_LIMIT_COLUMN] );
assert( pIdx->isResized==0 );
nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*(u64)N;
zExtra = sqlite3DbMallocZero(db, nByte);
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
pIdx->azColl = (const char**)zExtra;
zExtra += sizeof(char*)*N;
memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1));
pIdx->aiRowLogEst = (LogEst*)zExtra;
zExtra += sizeof(LogEst)*N;
memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
pIdx->aiColumn = (i16*)zExtra;
zExtra += sizeof(i16)*N;
memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
pIdx->aSortOrder = (u8*)zExtra;
pIdx->nColumn = (u16)N; /* See tag-20250221-1 above for proof of safety */
pIdx->isResized = 1;
return SQLITE_OK;
}
/*
** Estimate the total row width for a table.
*/
|
| ︙ | ︙ | |||
124611 124612 124613 124614 124615 124616 124617 |
}
}
if( n==0 ){
/* This index is a superset of the primary key */
pIdx->nColumn = pIdx->nKeyCol;
continue;
}
| | | 125157 125158 125159 125160 125161 125162 125163 125164 125165 125166 125167 125168 125169 125170 125171 |
}
}
if( n==0 ){
/* This index is a superset of the primary key */
pIdx->nColumn = pIdx->nKeyCol;
continue;
}
if( resizeIndexObject(pParse, pIdx, pIdx->nKeyCol+n) ) return;
for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
if( !isDupColumn(pIdx, pIdx->nKeyCol, pPk, i) ){
testcase( hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) );
pIdx->aiColumn[j] = pPk->aiColumn[i];
pIdx->azColl[j] = pPk->azColl[i];
if( pPk->aSortOrder[i] ){
/* See ticket https://www.sqlite.org/src/info/bba7b69f9849b5bf */
|
| ︙ | ︙ | |||
124635 124636 124637 124638 124639 124640 124641 |
/* Add all table columns to the PRIMARY KEY index
*/
nExtra = 0;
for(i=0; i<pTab->nCol; i++){
if( !hasColumn(pPk->aiColumn, nPk, i)
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
}
| | | 125181 125182 125183 125184 125185 125186 125187 125188 125189 125190 125191 125192 125193 125194 125195 |
/* Add all table columns to the PRIMARY KEY index
*/
nExtra = 0;
for(i=0; i<pTab->nCol; i++){
if( !hasColumn(pPk->aiColumn, nPk, i)
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ) nExtra++;
}
if( resizeIndexObject(pParse, pPk, nPk+nExtra) ) return;
for(i=0, j=nPk; i<pTab->nCol; i++){
if( !hasColumn(pPk->aiColumn, j, i)
&& (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0
){
assert( j<pPk->nColumn );
pPk->aiColumn[j] = i;
pPk->azColl[j] = sqlite3StrBINARY;
|
| ︙ | ︙ | |||
125793 125794 125795 125796 125797 125798 125799 |
sqlite3ErrorMsg(pParse,
"number of columns in foreign key does not match the number of "
"columns in the referenced table");
goto fk_end;
}else{
nCol = pFromCol->nExpr;
}
| | | 126339 126340 126341 126342 126343 126344 126345 126346 126347 126348 126349 126350 126351 126352 126353 |
sqlite3ErrorMsg(pParse,
"number of columns in foreign key does not match the number of "
"columns in the referenced table");
goto fk_end;
}else{
nCol = pFromCol->nExpr;
}
nByte = SZ_FKEY(nCol) + pTo->n + 1;
if( pToCol ){
for(i=0; i<pToCol->nExpr; i++){
nByte += sqlite3Strlen30(pToCol->a[i].zEName) + 1;
}
}
pFKey = sqlite3DbMallocZero(db, nByte );
if( pFKey==0 ){
|
| ︙ | ︙ | |||
126019 126020 126021 126022 126023 126024 126025 | ** ** Increase the allocation size to provide an extra nExtra bytes ** of 8-byte aligned space after the Index object and return a ** pointer to this extra space in *ppExtra. */ SQLITE_PRIVATE Index *sqlite3AllocateIndexObject( sqlite3 *db, /* Database connection */ | | > > | | | 126565 126566 126567 126568 126569 126570 126571 126572 126573 126574 126575 126576 126577 126578 126579 126580 126581 126582 126583 126584 126585 126586 126587 126588 126589 126590 126591 126592 126593 126594 126595 126596 126597 126598 126599 126600 126601 |
**
** Increase the allocation size to provide an extra nExtra bytes
** of 8-byte aligned space after the Index object and return a
** pointer to this extra space in *ppExtra.
*/
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(
sqlite3 *db, /* Database connection */
int nCol, /* Total number of columns in the index */
int nExtra, /* Number of bytes of extra space to alloc */
char **ppExtra /* Pointer to the "extra" space */
){
Index *p; /* Allocated index object */
i64 nByte; /* Bytes of space for Index object + arrays */
assert( nCol <= 2*db->aLimit[SQLITE_LIMIT_COLUMN] );
nByte = ROUND8(sizeof(Index)) + /* Index structure */
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
sizeof(i16)*nCol + /* Index.aiColumn */
sizeof(u8)*nCol); /* Index.aSortOrder */
p = sqlite3DbMallocZero(db, nByte + nExtra);
if( p ){
char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
p->azColl = (const char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
p->aSortOrder = (u8*)pExtra;
assert( nCol>0 );
p->nColumn = (u16)nCol;
p->nKeyCol = (u16)(nCol - 1);
*ppExtra = ((char*)p) + nByte;
}
return p;
}
/*
** If expression list pList contains an expression that was parsed with
|
| ︙ | ︙ | |||
126850 126851 126852 126853 126854 126855 126856 |
**
** A new IdList is returned, or NULL if malloc() fails.
*/
SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
| | | < | 127398 127399 127400 127401 127402 127403 127404 127405 127406 127407 127408 127409 127410 127411 127412 127413 127414 127415 127416 |
**
** A new IdList is returned, or NULL if malloc() fails.
*/
SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *pToken){
sqlite3 *db = pParse->db;
int i;
if( pList==0 ){
pList = sqlite3DbMallocZero(db, SZ_IDLIST(1));
if( pList==0 ) return 0;
}else{
IdList *pNew;
pNew = sqlite3DbRealloc(db, pList, SZ_IDLIST(pList->nId+1));
if( pNew==0 ){
sqlite3IdListDelete(db, pList);
return 0;
}
pList = pNew;
}
i = pList->nId++;
|
| ︙ | ︙ | |||
126954 126955 126956 126957 126958 126959 126960 |
if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){
sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d",
SQLITE_MAX_SRCLIST);
return 0;
}
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
| | < | 127501 127502 127503 127504 127505 127506 127507 127508 127509 127510 127511 127512 127513 127514 127515 |
if( pSrc->nSrc+nExtra>=SQLITE_MAX_SRCLIST ){
sqlite3ErrorMsg(pParse, "too many FROM clause terms, max: %d",
SQLITE_MAX_SRCLIST);
return 0;
}
if( nAlloc>SQLITE_MAX_SRCLIST ) nAlloc = SQLITE_MAX_SRCLIST;
pNew = sqlite3DbRealloc(db, pSrc, SZ_SRCLIST(nAlloc));
if( pNew==0 ){
assert( db->mallocFailed );
return 0;
}
pSrc = pNew;
pSrc->nAlloc = nAlloc;
}
|
| ︙ | ︙ | |||
127030 127031 127032 127033 127034 127035 127036 |
SrcItem *pItem;
sqlite3 *db;
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
assert( pParse!=0 );
assert( pParse->db!=0 );
db = pParse->db;
if( pList==0 ){
| | | 127576 127577 127578 127579 127580 127581 127582 127583 127584 127585 127586 127587 127588 127589 127590 |
SrcItem *pItem;
sqlite3 *db;
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
assert( pParse!=0 );
assert( pParse->db!=0 );
db = pParse->db;
if( pList==0 ){
pList = sqlite3DbMallocRawNN(pParse->db, SZ_SRCLIST(1));
if( pList==0 ) return 0;
pList->nAlloc = 1;
pList->nSrc = 1;
memset(&pList->a[0], 0, sizeof(pList->a[0]));
pList->a[0].iCursor = -1;
}else{
SrcList *pNew = sqlite3SrcListEnlarge(pParse, pList, 1, pList->nSrc);
|
| ︙ | ︙ | |||
127916 127917 127918 127919 127920 127921 127922 |
if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){
sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName);
}
}
}
if( pWith ){
| < | | | 128462 128463 128464 128465 128466 128467 128468 128469 128470 128471 128472 128473 128474 128475 128476 128477 128478 |
if( sqlite3StrICmp(zName, pWith->a[i].zName)==0 ){
sqlite3ErrorMsg(pParse, "duplicate WITH table name: %s", zName);
}
}
}
if( pWith ){
pNew = sqlite3DbRealloc(db, pWith, SZ_WITH(pWith->nCte+1));
}else{
pNew = sqlite3DbMallocZero(db, SZ_WITH(1));
}
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
if( db->mallocFailed ){
sqlite3CteDelete(db, pCte);
pNew = pWith;
}else{
|
| ︙ | ︙ | |||
130627 130628 130629 130630 130631 130632 130633 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; /* ** Append to pStr text that is the SQL literal representation of the ** value contained in pValue. */ | | | 131172 131173 131174 131175 131176 131177 131178 131179 131180 131181 131182 131183 131184 131185 131186 |
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
/*
** Append to pStr text that is the SQL literal representation of the
** value contained in pValue.
*/
SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue, int bEscape){
/* As currently implemented, the string must be initially empty.
** we might relax this requirement in the future, but that will
** require enhancements to the implementation. */
assert( pStr!=0 && pStr->nChar==0 );
switch( sqlite3_value_type(pValue) ){
case SQLITE_FLOAT: {
|
| ︙ | ︙ | |||
130675 130676 130677 130678 130679 130680 130681 |
zText[1] = '\'';
pStr->nChar = nBlob*2 + 3;
}
break;
}
case SQLITE_TEXT: {
const unsigned char *zArg = sqlite3_value_text(pValue);
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 131220 131221 131222 131223 131224 131225 131226 131227 131228 131229 131230 131231 131232 131233 131234 131235 131236 131237 131238 131239 131240 131241 131242 131243 131244 131245 131246 131247 131248 131249 131250 131251 131252 131253 131254 131255 131256 131257 131258 131259 131260 131261 131262 131263 131264 131265 131266 131267 131268 131269 131270 131271 131272 131273 131274 131275 131276 131277 131278 131279 131280 131281 131282 131283 131284 131285 131286 131287 131288 131289 131290 131291 131292 131293 131294 131295 131296 131297 131298 131299 131300 131301 131302 131303 131304 131305 131306 131307 131308 131309 131310 131311 131312 131313 131314 131315 131316 131317 131318 131319 131320 131321 131322 131323 131324 131325 131326 131327 131328 131329 131330 131331 131332 131333 131334 131335 131336 131337 131338 131339 131340 131341 131342 131343 131344 131345 131346 131347 131348 131349 131350 131351 131352 131353 131354 131355 131356 131357 131358 131359 131360 131361 131362 131363 131364 |
zText[1] = '\'';
pStr->nChar = nBlob*2 + 3;
}
break;
}
case SQLITE_TEXT: {
const unsigned char *zArg = sqlite3_value_text(pValue);
sqlite3_str_appendf(pStr, bEscape ? "%#Q" : "%Q", zArg);
break;
}
default: {
assert( sqlite3_value_type(pValue)==SQLITE_NULL );
sqlite3_str_append(pStr, "NULL", 4);
break;
}
}
}
/*
** Return true if z[] begins with N hexadecimal digits, and write
** a decoding of those digits into *pVal. Or return false if any
** one of the first N characters in z[] is not a hexadecimal digit.
*/
static int isNHex(const char *z, int N, u32 *pVal){
int i;
int v = 0;
for(i=0; i<N; i++){
if( !sqlite3Isxdigit(z[i]) ) return 0;
v = (v<<4) + sqlite3HexToInt(z[i]);
}
*pVal = v;
return 1;
}
/*
** Implementation of the UNISTR() function.
**
** This is intended to be a work-alike of the UNISTR() function in
** PostgreSQL. Quoting from the PG documentation (PostgreSQL 17 -
** scraped on 2025-02-22):
**
** Evaluate escaped Unicode characters in the argument. Unicode
** characters can be specified as \XXXX (4 hexadecimal digits),
** \+XXXXXX (6 hexadecimal digits), \uXXXX (4 hexadecimal digits),
** or \UXXXXXXXX (8 hexadecimal digits). To specify a backslash,
** write two backslashes. All other characters are taken literally.
*/
static void unistrFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
char *zOut;
const char *zIn;
int nIn;
int i, j, n;
u32 v;
assert( argc==1 );
UNUSED_PARAMETER( argc );
zIn = (const char*)sqlite3_value_text(argv[0]);
if( zIn==0 ) return;
nIn = sqlite3_value_bytes(argv[0]);
zOut = sqlite3_malloc64(nIn+1);
if( zOut==0 ){
sqlite3_result_error_nomem(context);
return;
}
i = j = 0;
while( i<nIn ){
char *z = strchr(&zIn[i],'\\');
if( z==0 ){
n = nIn - i;
memmove(&zOut[j], &zIn[i], n);
j += n;
break;
}
n = z - &zIn[i];
if( n>0 ){
memmove(&zOut[j], &zIn[i], n);
j += n;
i += n;
}
if( zIn[i+1]=='\\' ){
i += 2;
zOut[j++] = '\\';
}else if( sqlite3Isxdigit(zIn[i+1]) ){
if( !isNHex(&zIn[i+1], 4, &v) ) goto unistr_error;
i += 5;
j += sqlite3AppendOneUtf8Character(&zOut[j], v);
}else if( zIn[i+1]=='+' ){
if( !isNHex(&zIn[i+2], 6, &v) ) goto unistr_error;
i += 8;
j += sqlite3AppendOneUtf8Character(&zOut[j], v);
}else if( zIn[i+1]=='u' ){
if( !isNHex(&zIn[i+2], 4, &v) ) goto unistr_error;
i += 6;
j += sqlite3AppendOneUtf8Character(&zOut[j], v);
}else if( zIn[i+1]=='U' ){
if( !isNHex(&zIn[i+2], 8, &v) ) goto unistr_error;
i += 10;
j += sqlite3AppendOneUtf8Character(&zOut[j], v);
}else{
goto unistr_error;
}
}
zOut[j] = 0;
sqlite3_result_text64(context, zOut, j, sqlite3_free, SQLITE_UTF8);
return;
unistr_error:
sqlite3_free(zOut);
sqlite3_result_error(context, "invalid Unicode escape", -1);
return;
}
/*
** Implementation of the QUOTE() function.
**
** The quote(X) function returns the text of an SQL literal which is the
** value of its argument suitable for inclusion into an SQL statement.
** Strings are surrounded by single-quotes with escapes on interior quotes
** as needed. BLOBs are encoded as hexadecimal literals. Strings with
** embedded NUL characters cannot be represented as string literals in SQL
** and hence the returned string literal is truncated prior to the first NUL.
**
** If sqlite3_user_data() is non-zero, then the UNISTR_QUOTE() function is
** implemented instead. The difference is that UNISTR_QUOTE() uses the
** UNISTR() function to escape control characters.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
sqlite3_str str;
sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==1 );
UNUSED_PARAMETER(argc);
sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
sqlite3QuoteValue(&str,argv[0],SQLITE_PTR_TO_INT(sqlite3_user_data(context)));
sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
SQLITE_DYNAMIC);
if( str.accError!=SQLITE_OK ){
sqlite3_result_null(context);
sqlite3_result_error_code(context, str.accError);
}
}
|
| ︙ | ︙ | |||
131353 131354 131355 131356 131357 131358 131359 | /* ** Routines used to compute the sum, average, and total. ** ** The SUM() function follows the (broken) SQL standard which means ** that it returns NULL if it sums over no inputs. TOTAL returns ** 0.0 in that case. In addition, TOTAL always returns a float where ** SUM might return an integer if it never encounters a floating point | | | 132001 132002 132003 132004 132005 132006 132007 132008 132009 132010 132011 132012 132013 132014 132015 |
/*
** Routines used to compute the sum, average, and total.
**
** The SUM() function follows the (broken) SQL standard which means
** that it returns NULL if it sums over no inputs. TOTAL returns
** 0.0 in that case. In addition, TOTAL always returns a float where
** SUM might return an integer if it never encounters a floating point
** value. TOTAL never fails, but SUM might throw an exception if
** it overflows an integer.
*/
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
SumCtx *p;
int type;
assert( argc==1 );
UNUSED_PARAMETER(argc);
|
| ︙ | ︙ | |||
132273 132274 132275 132276 132277 132278 132279 132280 132281 132282 132283 132284 132285 132286 132287 |
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
| > > | 132921 132922 132923 132924 132925 132926 132927 132928 132929 132930 132931 132932 132933 132934 132935 132936 132937 |
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
FUNCTION(unistr, 1, 0, 0, unistrFunc ),
FUNCTION(quote, 1, 0, 0, quoteFunc ),
FUNCTION(unistr_quote, 1, 1, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
VFUNCTION(changes, 0, 0, 0, changes ),
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
FUNCTION(substr, 2, 0, 0, substrFunc ),
FUNCTION(substr, 3, 0, 0, substrFunc ),
|
| ︙ | ︙ | |||
134560 134561 134562 134563 134564 134565 134566 |
sqlite3MultiValuesEnd(pParse, pLeft);
f = SF_Values;
}else if( pLeft->pPrior ){
/* In this case set the SF_MultiValue flag only if it was set on pLeft */
f = (f & pLeft->selFlags);
}
pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
| | | 135210 135211 135212 135213 135214 135215 135216 135217 135218 135219 135220 135221 135222 135223 135224 |
sqlite3MultiValuesEnd(pParse, pLeft);
f = SF_Values;
}else if( pLeft->pPrior ){
/* In this case set the SF_MultiValue flag only if it was set on pLeft */
f = (f & pLeft->selFlags);
}
pSelect = sqlite3SelectNew(pParse, pRow, 0, 0, 0, 0, 0, f, 0);
pLeft->selFlags &= ~(u32)SF_MultiValue;
if( pSelect ){
pSelect->op = TK_ALL;
pSelect->pPrior = pLeft;
pLeft = pSelect;
}
}else{
SrcItem *p = 0; /* SrcItem that reads from co-routine */
|
| ︙ | ︙ | |||
139166 139167 139168 139169 139170 139171 139172 |
/* 9 */ "name",
/* 10 */ "type",
/* 11 */ "notnull",
/* 12 */ "dflt_value",
/* 13 */ "pk",
/* 14 */ "hidden",
/* table_info reuses 8 */
| | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | > | 139816 139817 139818 139819 139820 139821 139822 139823 139824 139825 139826 139827 139828 139829 139830 139831 139832 139833 139834 139835 139836 139837 139838 139839 139840 139841 139842 139843 139844 139845 139846 139847 139848 139849 139850 139851 139852 139853 139854 139855 139856 139857 139858 139859 139860 139861 139862 139863 139864 139865 139866 139867 139868 139869 139870 139871 |
/* 9 */ "name",
/* 10 */ "type",
/* 11 */ "notnull",
/* 12 */ "dflt_value",
/* 13 */ "pk",
/* 14 */ "hidden",
/* table_info reuses 8 */
/* 15 */ "name", /* Used by: function_list */
/* 16 */ "builtin",
/* 17 */ "type",
/* 18 */ "enc",
/* 19 */ "narg",
/* 20 */ "flags",
/* 21 */ "schema", /* Used by: table_list */
/* 22 */ "name",
/* 23 */ "type",
/* 24 */ "ncol",
/* 25 */ "wr",
/* 26 */ "strict",
/* 27 */ "seqno", /* Used by: index_xinfo */
/* 28 */ "cid",
/* 29 */ "name",
/* 30 */ "desc",
/* 31 */ "coll",
/* 32 */ "key",
/* 33 */ "seq", /* Used by: index_list */
/* 34 */ "name",
/* 35 */ "unique",
/* 36 */ "origin",
/* 37 */ "partial",
/* 38 */ "tbl", /* Used by: stats */
/* 39 */ "idx",
/* 40 */ "wdth",
/* 41 */ "hght",
/* 42 */ "flgs",
/* 43 */ "table", /* Used by: foreign_key_check */
/* 44 */ "rowid",
/* 45 */ "parent",
/* 46 */ "fkid",
/* 47 */ "busy", /* Used by: wal_checkpoint */
/* 48 */ "log",
/* 49 */ "checkpointed",
/* 50 */ "seq", /* Used by: database_list */
/* 51 */ "name",
/* 52 */ "file",
/* index_info reuses 27 */
/* 53 */ "database", /* Used by: lock_status */
/* 54 */ "status",
/* collation_list reuses 33 */
/* 55 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */
/* 56 */ "timeout", /* Used by: busy_timeout */
};
/* Definitions of all built-in pragmas */
typedef struct PragmaName {
|
| ︙ | ︙ | |||
139300 139301 139302 139303 139304 139305 139306 |
/* ColNames: */ 0, 0,
/* iArg: */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0,
| | | 139950 139951 139952 139953 139954 139955 139956 139957 139958 139959 139960 139961 139962 139963 139964 |
/* ColNames: */ 0, 0,
/* iArg: */ SQLITE_CkptFullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 33, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
{/* zName: */ "compile_options",
/* ePragTyp: */ PragTyp_COMPILE_OPTIONS,
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 0, 0,
|
| ︙ | ︙ | |||
139335 139336 139337 139338 139339 139340 139341 |
/* ColNames: */ 0, 0,
/* iArg: */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_Result0,
| | | 139985 139986 139987 139988 139989 139990 139991 139992 139993 139994 139995 139996 139997 139998 139999 |
/* ColNames: */ 0, 0,
/* iArg: */ BTREE_DATA_VERSION },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 50, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
{/* zName: */ "default_cache_size",
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
/* ColNames: */ 55, 1,
|
| ︙ | ︙ | |||
139415 139416 139417 139418 139419 139420 139421 |
/* iArg: */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
{/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0,
| | | 140065 140066 140067 140068 140069 140070 140071 140072 140073 140074 140075 140076 140077 140078 140079 |
/* iArg: */ SQLITE_FullFSync },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
#if !defined(SQLITE_OMIT_INTROSPECTION_PRAGMAS)
{/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 15, 6,
/* iArg: */ 0 },
#endif
#endif
{/* zName: */ "hard_heap_limit",
/* ePragTyp: */ PragTyp_HARD_HEAP_LIMIT,
/* ePragFlg: */ PragFlg_Result0,
/* ColNames: */ 0, 0,
|
| ︙ | ︙ | |||
139444 139445 139446 139447 139448 139449 139450 |
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
| | | | | 140094 140095 140096 140097 140098 140099 140100 140101 140102 140103 140104 140105 140106 140107 140108 140109 140110 140111 140112 140113 140114 140115 140116 140117 140118 |
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 27, 3,
/* iArg: */ 0 },
{/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 33, 5,
/* iArg: */ 0 },
{/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 27, 6,
/* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "integrity_check",
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 0, 0,
|
| ︙ | ︙ | |||
139633 139634 139635 139636 139637 139638 139639 |
/* iArg: */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
{/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
| | | | 140283 140284 140285 140286 140287 140288 140289 140290 140291 140292 140293 140294 140295 140296 140297 140298 140299 140300 140301 140302 140303 140304 140305 140306 140307 140308 140309 140310 140311 140312 140313 140314 140315 140316 |
/* iArg: */ SQLITE_SqlTrace },
#endif
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
{/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
/* ColNames: */ 38, 5,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "synchronous",
/* ePragTyp: */ PragTyp_SYNCHRONOUS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
{/* zName: */ "table_info",
/* ePragTyp: */ PragTyp_TABLE_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 8, 6,
/* iArg: */ 0 },
{/* zName: */ "table_list",
/* ePragTyp: */ PragTyp_TABLE_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
/* ColNames: */ 21, 6,
/* iArg: */ 0 },
{/* zName: */ "table_xinfo",
/* ePragTyp: */ PragTyp_TABLE_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
/* ColNames: */ 8, 7,
/* iArg: */ 1 },
#endif
|
| ︙ | ︙ | |||
139729 139730 139731 139732 139733 139734 139735 |
/* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
{/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema,
| | | 140379 140380 140381 140382 140383 140384 140385 140386 140387 140388 140389 140390 140391 140392 140393 |
/* ePragTyp: */ PragTyp_WAL_AUTOCHECKPOINT,
/* ePragFlg: */ 0,
/* ColNames: */ 0, 0,
/* iArg: */ 0 },
{/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema,
/* ColNames: */ 47, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{/* zName: */ "writable_schema",
/* ePragTyp: */ PragTyp_FLAG,
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
/* ColNames: */ 0, 0,
|
| ︙ | ︙ | |||
139751 139752 139753 139754 139755 139756 139757 | /* ** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands ** will be run with an analysis_limit set to the lessor of the value of ** the following macro or to the actual analysis_limit if it is non-zero, ** in order to prevent PRAGMA optimize from running for too long. ** | | | 140401 140402 140403 140404 140405 140406 140407 140408 140409 140410 140411 140412 140413 140414 140415 | /* ** When the 0x10 bit of PRAGMA optimize is set, any ANALYZE commands ** will be run with an analysis_limit set to the lessor of the value of ** the following macro or to the actual analysis_limit if it is non-zero, ** in order to prevent PRAGMA optimize from running for too long. ** ** The value of 2000 is chosen empirically so that the worst-case run-time ** for PRAGMA optimize does not exceed 100 milliseconds against a variety ** of test databases on a RaspberryPI-4 compiled using -Os and without ** -DSQLITE_DEBUG. Of course, your mileage may vary. For the purpose of ** this paragraph, "worst-case" means that ANALYZE ends up being ** run on every table in the database. The worst case typically only ** happens if PRAGMA optimize is run on a database file for which ANALYZE ** has not been previously run and the 0x10000 flag is included so that |
| ︙ | ︙ | |||
144040 144041 144042 144043 144044 144045 144046 | pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; | | | 144690 144691 144692 144693 144694 144695 144696 144697 144698 144699 144700 144701 144702 144703 144704 | pNew->selFlags = selFlags; pNew->iLimit = 0; pNew->iOffset = 0; pNew->selId = ++pParse->nSelect; pNew->addrOpenEphm[0] = -1; pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = 0; if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1); pNew->pSrc = pSrc; pNew->pWhere = pWhere; pNew->pGroupBy = pGroupBy; pNew->pHaving = pHaving; pNew->pOrderBy = pOrderBy; pNew->pPrior = 0; pNew->pNext = 0; |
| ︙ | ︙ | |||
145423 145424 145425 145426 145427 145428 145429 |
}
/*
** Allocate a KeyInfo object sufficient for an index of N key columns and
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
| | | | | 146073 146074 146075 146076 146077 146078 146079 146080 146081 146082 146083 146084 146085 146086 146087 146088 146089 146090 146091 146092 146093 146094 146095 146096 |
}
/*
** Allocate a KeyInfo object sufficient for an index of N key columns and
** X extra columns.
*/
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
int nExtra = (N+X)*(sizeof(CollSeq*)+1);
KeyInfo *p = sqlite3DbMallocRawNN(db, SZ_KEYINFO(0) + nExtra);
if( p ){
p->aSortFlags = (u8*)&p->aColl[N+X];
p->nKeyField = (u16)N;
p->nAllField = (u16)(N+X);
p->enc = ENC(db);
p->db = db;
p->nRef = 1;
memset(p->aColl, 0, nExtra);
}else{
return (KeyInfo*)sqlite3OomFault(db);
}
return p;
}
/*
|
| ︙ | ︙ | |||
149532 149533 149534 149535 149536 149537 149538 | pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; p->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC p->pWinDefn = 0; #endif | | | 150182 150183 150184 150185 150186 150187 150188 150189 150190 150191 150192 150193 150194 150195 150196 | pNew->pOrderBy = 0; p->pPrior = 0; p->pNext = 0; p->pWith = 0; #ifndef SQLITE_OMIT_WINDOWFUNC p->pWinDefn = 0; #endif p->selFlags &= ~(u32)SF_Compound; assert( (p->selFlags & SF_Converted)==0 ); p->selFlags |= SF_Converted; assert( pNew->pPrior!=0 ); pNew->pPrior->pNext = pNew; pNew->pLimit = 0; return WRC_Continue; } |
| ︙ | ︙ | |||
149948 149949 149950 149951 149952 149953 149954 |
/* Renumber selId because it has been copied from a view */
p->selId = ++pParse->nSelect;
}
pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->pWith && (p->selFlags & SF_View) ){
if( p->pWith==0 ){
| | | 150598 150599 150600 150601 150602 150603 150604 150605 150606 150607 150608 150609 150610 150611 150612 |
/* Renumber selId because it has been copied from a view */
p->selId = ++pParse->nSelect;
}
pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->pWith && (p->selFlags & SF_View) ){
if( p->pWith==0 ){
p->pWith = (With*)sqlite3DbMallocZero(db, SZ_WITH(1) );
if( p->pWith==0 ){
return WRC_Abort;
}
}
p->pWith->bView = 1;
}
sqlite3WithPush(pParse, p->pWith, 0);
|
| ︙ | ︙ | |||
151087 151088 151089 151090 151091 151092 151093 151094 151095 151096 151097 151098 151099 151100 |
** The transformation only works if all of the following are true:
**
** * The subquery is a UNION ALL of two or more terms
** * The subquery does not have a LIMIT clause
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
** * The outer query is a simple count(*) with no WHERE clause or other
** extraneous syntax.
**
** Return TRUE if the optimization is undertaken.
*/
static int countOfViewOptimization(Parse *pParse, Select *p){
Select *pSub, *pPrior;
Expr *pExpr;
Expr *pCount;
| > | 151737 151738 151739 151740 151741 151742 151743 151744 151745 151746 151747 151748 151749 151750 151751 |
** The transformation only works if all of the following are true:
**
** * The subquery is a UNION ALL of two or more terms
** * The subquery does not have a LIMIT clause
** * There is no WHERE or GROUP BY or HAVING clauses on the subqueries
** * The outer query is a simple count(*) with no WHERE clause or other
** extraneous syntax.
** * None of the subqueries are DISTINCT (forumpost/a860f5fb2e 2025-03-10)
**
** Return TRUE if the optimization is undertaken.
*/
static int countOfViewOptimization(Parse *pParse, Select *p){
Select *pSub, *pPrior;
Expr *pExpr;
Expr *pCount;
|
| ︙ | ︙ | |||
151119 151120 151121 151122 151123 151124 151125 |
pSub = pFrom->u4.pSubq->pSelect;
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
| > | > > > | | | | 151770 151771 151772 151773 151774 151775 151776 151777 151778 151779 151780 151781 151782 151783 151784 151785 151786 151787 151788 151789 151790 151791 151792 151793 151794 151795 151796 151797 151798 151799 151800 151801 151802 151803 151804 151805 151806 151807 151808 151809 151810 151811 151812 151813 151814 151815 151816 151817 151818 151819 151820 151821 151822 |
pSub = pFrom->u4.pSubq->pSelect;
if( pSub->pPrior==0 ) return 0; /* Must be a compound */
if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & (SF_Aggregate|SF_Distinct) ){
testcase( pSub->selFlags & SF_Aggregate );
testcase( pSub->selFlags & SF_Distinct );
return 0; /* Not an aggregate nor DISTINCT */
}
assert( pSub->pHaving==0 ); /* Due to the previous */
pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
db = pParse->db;
pCount = pExpr;
pExpr = 0;
pSub = sqlite3SubqueryDetach(db, pFrom);
sqlite3SrcListDelete(db, p->pSrc);
p->pSrc = sqlite3DbMallocZero(pParse->db, SZ_SRCLIST_1);
while( pSub ){
Expr *pTerm;
pPrior = pSub->pPrior;
pSub->pPrior = 0;
pSub->pNext = 0;
pSub->selFlags |= SF_Aggregate;
pSub->selFlags &= ~(u32)SF_Compound;
pSub->nSelectRow = 0;
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
sqlite3PExprAddSelect(pParse, pTerm, pSub);
if( pExpr==0 ){
pExpr = pTerm;
}else{
pExpr = sqlite3PExpr(pParse, TK_PLUS, pTerm, pExpr);
}
pSub = pPrior;
}
p->pEList->a[0].pExpr = pExpr;
p->selFlags &= ~(u32)SF_Aggregate;
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x200 ){
TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n"));
sqlite3TreeViewSelect(0, p, 0);
}
#endif
|
| ︙ | ︙ | |||
151360 151361 151362 151363 151364 151365 151366 |
}
#endif
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
p->pOrderBy);
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
| | | 152015 152016 152017 152018 152019 152020 152021 152022 152023 152024 152025 152026 152027 152028 152029 |
}
#endif
sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
p->pOrderBy);
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
p->selFlags &= ~(u32)SF_Distinct;
p->selFlags |= SF_NoopOrderBy;
}
sqlite3SelectPrep(pParse, p, 0);
if( pParse->nErr ){
goto select_end;
}
assert( db->mallocFailed==0 );
|
| ︙ | ︙ | |||
151399 151400 151401 151402 151403 151404 151405 |
goto select_end;
}
/* Clear the SF_UFSrcCheck flag. The check has already been performed,
** and leaving this flag set can cause errors if a compound sub-query
** in p->pSrc is flattened into this query and this function called
** again as part of compound SELECT processing. */
| | | 152054 152055 152056 152057 152058 152059 152060 152061 152062 152063 152064 152065 152066 152067 152068 |
goto select_end;
}
/* Clear the SF_UFSrcCheck flag. The check has already been performed,
** and leaving this flag set can cause errors if a compound sub-query
** in p->pSrc is flattened into this query and this function called
** again as part of compound SELECT processing. */
p->selFlags &= ~(u32)SF_UFSrcCheck;
}
if( pDest->eDest==SRT_Output ){
sqlite3GenerateColumnNames(pParse, p);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
|
| ︙ | ︙ | |||
151888 151889 151890 151891 151892 151893 151894 |
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
&& OptimizationEnabled(db, SQLITE_GroupByOrder)
#ifndef SQLITE_OMIT_WINDOWFUNC
&& p->pWin==0
#endif
){
| | | 152543 152544 152545 152546 152547 152548 152549 152550 152551 152552 152553 152554 152555 152556 152557 |
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
&& OptimizationEnabled(db, SQLITE_GroupByOrder)
#ifndef SQLITE_OMIT_WINDOWFUNC
&& p->pWin==0
#endif
){
p->selFlags &= ~(u32)SF_Distinct;
pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 0);
if( pGroupBy ){
for(i=0; i<pGroupBy->nExpr; i++){
pGroupBy->a[i].u.x.iOrderByCol = i+1;
}
}
p->selFlags |= SF_Aggregate;
|
| ︙ | ︙ | |||
153922 153923 153924 153925 153926 153927 153928 |
int regIn /* The first in an array of registers */
){
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
ExprList *pNew;
Returning *pReturning;
Select sSelect;
| | > > | | | | | | | 154577 154578 154579 154580 154581 154582 154583 154584 154585 154586 154587 154588 154589 154590 154591 154592 154593 154594 154595 154596 154597 154598 154599 154600 154601 154602 154603 154604 154605 154606 154607 154608 154609 154610 154611 154612 154613 154614 154615 |
int regIn /* The first in an array of registers */
){
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
ExprList *pNew;
Returning *pReturning;
Select sSelect;
SrcList *pFrom;
u8 fromSpace[SZ_SRCLIST_1];
assert( v!=0 );
if( !pParse->bReturning ){
/* This RETURNING trigger must be for a different statement as
** this statement lacks a RETURNING clause. */
return;
}
assert( db->pParse==pParse );
assert( !pParse->isCreate );
pReturning = pParse->u1.d.pReturning;
if( pTrigger != &(pReturning->retTrig) ){
/* This RETURNING trigger is for a different statement */
return;
}
memset(&sSelect, 0, sizeof(sSelect));
pFrom = (SrcList*)fromSpace;
memset(pFrom, 0, SZ_SRCLIST_1);
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
sSelect.pSrc = pFrom;
pFrom->nSrc = 1;
pFrom->a[0].pSTab = pTab;
pFrom->a[0].zName = pTab->zName; /* tag-20240424-1 */
pFrom->a[0].iCursor = -1;
sqlite3SelectPrep(pParse, &sSelect, 0);
if( pParse->nErr==0 ){
assert( db->mallocFailed==0 );
sqlite3GenerateColumnNames(pParse, &sSelect);
}
sqlite3ExprListDelete(db, sSelect.pEList);
pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
|
| ︙ | ︙ | |||
156345 156346 156347 156348 156349 156350 156351 | ** restored before returning. Then set the writable-schema flag, and ** disable CHECK and foreign key constraints. */ saved_flags = db->flags; saved_mDbFlags = db->mDbFlags; saved_nChange = db->nChange; saved_nTotalChange = db->nTotalChange; saved_mTrace = db->mTrace; | | | 157002 157003 157004 157005 157006 157007 157008 157009 157010 157011 157012 157013 157014 157015 157016 |
** restored before returning. Then set the writable-schema flag, and
** disable CHECK and foreign key constraints. */
saved_flags = db->flags;
saved_mDbFlags = db->mDbFlags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_mTrace = db->mTrace;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_Comments;
db->mDbFlags |= DBFLAG_PreferBuiltin | DBFLAG_Vacuum;
db->flags &= ~(u64)(SQLITE_ForeignKeys | SQLITE_ReverseOrder
| SQLITE_Defensive | SQLITE_CountRows);
db->mTrace = 0;
zDbMain = db->aDb[iDb].zDbSName;
pMain = db->aDb[iDb].pBt;
|
| ︙ | ︙ | |||
158474 158475 158476 158477 158478 158479 158480 | int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ | | > > > > > | 159131 159132 159133 159134 159135 159136 159137 159138 159139 159140 159141 159142 159143 159144 159145 159146 159147 159148 159149 159150 159151 159152 | int iTop; /* The very beginning of the WHERE loop */ int iEndWhere; /* End of the WHERE clause itself */ WhereLoop *pLoops; /* List of all WhereLoop objects */ WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */ Bitmask revMask; /* Mask of ORDER BY terms that need reversing */ WhereClause sWC; /* Decomposition of the WHERE clause */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereLevel a[FLEXARRAY]; /* Information about each nest loop in WHERE */ }; /* ** The size (in bytes) of a WhereInfo object that holds N WhereLevels. */ #define SZ_WHEREINFO(N) ROUND8(offsetof(WhereInfo,a)+(N)*sizeof(WhereLevel)) /* ** Private interfaces - callable only by other where.c routines. ** ** where.c: */ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); #ifdef WHERETRACE_ENABLED |
| ︙ | ︙ | |||
160927 160928 160929 160930 160931 160932 160933 |
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
*/
if( pWInfo->nLevel>1 ){
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
| | < | 161589 161590 161591 161592 161593 161594 161595 161596 161597 161598 161599 161600 161601 161602 161603 |
** by this loop in the a[0] slot and all notReady tables in a[1..] slots.
** This becomes the SrcList in the recursive call to sqlite3WhereBegin().
*/
if( pWInfo->nLevel>1 ){
int nNotReady; /* The number of notReady tables */
SrcItem *origSrc; /* Original list of tables */
nNotReady = pWInfo->nLevel - iLevel - 1;
pOrTab = sqlite3DbMallocRawNN(db, SZ_SRCLIST(nNotReady+1));
if( pOrTab==0 ) return notReady;
pOrTab->nAlloc = (u8)(nNotReady + 1);
pOrTab->nSrc = pOrTab->nAlloc;
memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem));
origSrc = pWInfo->pTabList->a;
for(k=1; k<=nNotReady; k++){
memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k]));
|
| ︙ | ︙ | |||
161471 161472 161473 161474 161475 161476 161477 | Vdbe *v = pParse->pVdbe; WhereRightJoin *pRJ = pLevel->pRJ; Expr *pSubWhere = 0; WhereClause *pWC = &pWInfo->sWC; WhereInfo *pSubWInfo; WhereLoop *pLoop = pLevel->pWLoop; SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; | | > | 162132 162133 162134 162135 162136 162137 162138 162139 162140 162141 162142 162143 162144 162145 162146 162147 |
Vdbe *v = pParse->pVdbe;
WhereRightJoin *pRJ = pLevel->pRJ;
Expr *pSubWhere = 0;
WhereClause *pWC = &pWInfo->sWC;
WhereInfo *pSubWInfo;
WhereLoop *pLoop = pLevel->pWLoop;
SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
SrcList *pFrom;
u8 fromSpace[SZ_SRCLIST_1];
Bitmask mAll = 0;
int k;
ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName));
sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
pRJ->regReturn);
for(k=0; k<iLevel; k++){
|
| ︙ | ︙ | |||
161515 161516 161517 161518 161519 161520 161521 |
}
if( pTerm->prereqAll & ~mAll ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
| > | | | | | | 162177 162178 162179 162180 162181 162182 162183 162184 162185 162186 162187 162188 162189 162190 162191 162192 162193 162194 162195 162196 162197 162198 |
}
if( pTerm->prereqAll & ~mAll ) continue;
if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
}
}
pFrom = (SrcList*)fromSpace;
pFrom->nSrc = 1;
pFrom->nAlloc = 1;
memcpy(&pFrom->a[0], pTabItem, sizeof(SrcItem));
pFrom->a[0].fg.jointype = 0;
assert( pParse->withinRJSubrtn < 100 );
pParse->withinRJSubrtn++;
pSubWInfo = sqlite3WhereBegin(pParse, pFrom, pSubWhere, 0, 0, 0,
WHERE_RIGHT_JOIN, 0);
if( pSubWInfo ){
int iCur = pLevel->iTabCur;
int r = ++pParse->nMem;
int nPk;
int jmp;
int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
|
| ︙ | ︙ | |||
163509 163510 163511 163512 163513 163514 163515 |
typedef struct HiddenIndexInfo HiddenIndexInfo;
struct HiddenIndexInfo {
WhereClause *pWC; /* The Where clause being analyzed */
Parse *pParse; /* The parsing context */
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
u32 mIn; /* Mask of terms that are <col> IN (...) */
u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
| | | | > > > > > | 164172 164173 164174 164175 164176 164177 164178 164179 164180 164181 164182 164183 164184 164185 164186 164187 164188 164189 164190 164191 164192 164193 164194 164195 |
typedef struct HiddenIndexInfo HiddenIndexInfo;
struct HiddenIndexInfo {
WhereClause *pWC; /* The Where clause being analyzed */
Parse *pParse; /* The parsing context */
int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
u32 mIn; /* Mask of terms that are <col> IN (...) */
u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
sqlite3_value *aRhs[FLEXARRAY]; /* RHS values for constraints. MUST BE LAST
** Extra space is allocated to hold up
** to nTerm such values */
};
/* Size (in bytes) of a HiddenIndeInfo object sufficient to hold as
** many as N constraints */
#define SZ_HIDDENINDEXINFO(N) \
(offsetof(HiddenIndexInfo,aRhs) + (N)*sizeof(sqlite3_value*))
/* Forward declaration of methods */
static int whereLoopResize(sqlite3*, WhereLoop*, int);
/*
** Return the estimated number of output rows from a WHERE clause
*/
SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo *pWInfo){
|
| ︙ | ︙ | |||
164578 164579 164580 164581 164582 164583 164584 164585 164586 164587 164588 164589 164590 164591 |
if( extraCols & MASKBIT(i) ) nKeyCol++;
}
if( pSrc->colUsed & MASKBIT(BMS-1) ){
nKeyCol += pTable->nCol - BMS + 1;
}
/* Construct the Index object to describe this index */
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
0, &zNotUsed);
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
pIdx->pTable = pTable;
n = 0;
| > > | 165246 165247 165248 165249 165250 165251 165252 165253 165254 165255 165256 165257 165258 165259 165260 165261 |
if( extraCols & MASKBIT(i) ) nKeyCol++;
}
if( pSrc->colUsed & MASKBIT(BMS-1) ){
nKeyCol += pTable->nCol - BMS + 1;
}
/* Construct the Index object to describe this index */
assert( nKeyCol <= pTable->nCol + MAX(0, pTable->nCol - BMS + 1) );
/* ^-- This guarantees that the number of index columns will fit in the u16 */
pIdx = sqlite3AllocateIndexObject(pParse->db, nKeyCol+HasRowid(pTable),
0, &zNotUsed);
if( pIdx==0 ) goto end_auto_index_create;
pLoop->u.btree.pIndex = pIdx;
pIdx->zName = "auto-index";
pIdx->pTable = pTable;
n = 0;
|
| ︙ | ︙ | |||
164989 164990 164991 164992 164993 164994 164995 |
}
}
/* Allocate the sqlite3_index_info structure
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
| | | | 165659 165660 165661 165662 165663 165664 165665 165666 165667 165668 165669 165670 165671 165672 165673 165674 |
}
}
/* Allocate the sqlite3_index_info structure
*/
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
+ sizeof(*pIdxOrderBy)*nOrderBy
+ SZ_HIDDENINDEXINFO(nTerm) );
if( pIdxInfo==0 ){
sqlite3ErrorMsg(pParse, "out of memory");
return 0;
}
pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm];
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
|
| ︙ | ︙ | |||
170184 170185 170186 170187 170188 170189 170190 | /* Allocate and initialize the WhereInfo structure that will become the ** return value. A single allocation is used to store the WhereInfo ** struct, the contents of WhereInfo.a[], the WhereClause structure ** and the WhereMaskSet structure. Since WhereClause contains an 8-byte ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ | | < < < | 170854 170855 170856 170857 170858 170859 170860 170861 170862 170863 170864 170865 170866 170867 170868 |
/* Allocate and initialize the WhereInfo structure that will become the
** return value. A single allocation is used to store the WhereInfo
** struct, the contents of WhereInfo.a[], the WhereClause structure
** and the WhereMaskSet structure. Since WhereClause contains an 8-byte
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
nByteWInfo = SZ_WHEREINFO(nTabList);
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
pWInfo = 0;
goto whereBeginError;
}
pWInfo->pParse = pParse;
|
| ︙ | ︙ | |||
172139 172140 172141 172142 172143 172144 172145 |
sqlite3WalkExprList(&w, p->pOrderBy);
}
p->pSrc = 0;
p->pWhere = 0;
p->pGroupBy = 0;
p->pHaving = 0;
| | | 172806 172807 172808 172809 172810 172811 172812 172813 172814 172815 172816 172817 172818 172819 172820 |
sqlite3WalkExprList(&w, p->pOrderBy);
}
p->pSrc = 0;
p->pWhere = 0;
p->pGroupBy = 0;
p->pHaving = 0;
p->selFlags &= ~(u32)SF_Aggregate;
p->selFlags |= SF_WinRewrite;
/* Create the ORDER BY clause for the sub-select. This is the concatenation
** of the window PARTITION and ORDER BY clauses. Then, if this makes it
** redundant, remove the ORDER BY from the parent SELECT. */
pSort = exprListAppendList(pParse, 0, pMWin->pPartition, 1);
pSort = exprListAppendList(pParse, pSort, pMWin->pOrderBy, 1);
|
| ︙ | ︙ | |||
178278 178279 178280 178281 178282 178283 178284 |
parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
pRhs->op = (u8)yymsp[-1].minor.yy502;
pRhs->pPrior = pLhs;
| | | | 178945 178946 178947 178948 178949 178950 178951 178952 178953 178954 178955 178956 178957 178958 178959 178960 |
parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
}
if( pRhs ){
pRhs->op = (u8)yymsp[-1].minor.yy502;
pRhs->pPrior = pLhs;
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~(u32)SF_MultiValue;
pRhs->selFlags &= ~(u32)SF_MultiValue;
if( yymsp[-1].minor.yy502!=TK_ALL ) pParse->hasCompound = 1;
}else{
sqlite3SelectDelete(pParse->db, pLhs);
}
yymsp[-2].minor.yy637 = pRhs;
}
break;
|
| ︙ | ︙ | |||
181023 181024 181025 181026 181027 181028 181029 |
}else if( tokenType==TK_OVER ){
assert( n==4 );
tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
}else if( tokenType==TK_FILTER ){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
| | > > > > | 181690 181691 181692 181693 181694 181695 181696 181697 181698 181699 181700 181701 181702 181703 181704 181705 181706 181707 181708 |
}else if( tokenType==TK_OVER ){
assert( n==4 );
tokenType = analyzeOverKeyword((const u8*)&zSql[4], lastTokenParsed);
}else if( tokenType==TK_FILTER ){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif /* SQLITE_OMIT_WINDOWFUNC */
}else if( tokenType==TK_COMMENT
&& (db->init.busy || (db->flags & SQLITE_Comments)!=0)
){
/* Ignore SQL comments if either (1) we are reparsing the schema or
** (2) SQLITE_DBCONFIG_ENABLE_COMMENTS is turned on (the default). */
zSql += n;
continue;
}else if( tokenType!=TK_QNUMBER ){
Token x;
x.z = zSql;
x.n = n;
sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x);
|
| ︙ | ︙ | |||
181918 181919 181920 181921 181922 181923 181924 181925 181926 181927 181928 181929 181930 181931 |
if( rc==SQLITE_OK ){
rc = sqlite3MemdbInit();
}
#endif
if( rc==SQLITE_OK ){
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
sqlite3MemoryBarrier();
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
bRunExtraInit = 1;
#endif
}
sqlite3GlobalConfig.inProgress = 0;
| > > > > > > > > | 182589 182590 182591 182592 182593 182594 182595 182596 182597 182598 182599 182600 182601 182602 182603 182604 182605 182606 182607 182608 182609 182610 |
if( rc==SQLITE_OK ){
rc = sqlite3MemdbInit();
}
#endif
if( rc==SQLITE_OK ){
sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
#ifdef SQLITE_EXTRA_INIT_MUTEXED
{
int SQLITE_EXTRA_INIT_MUTEXED(const char*);
rc = SQLITE_EXTRA_INIT_MUTEXED(0);
}
#endif
}
if( rc==SQLITE_OK ){
sqlite3MemoryBarrier();
sqlite3GlobalConfig.isInit = 1;
#ifdef SQLITE_EXTRA_INIT
bRunExtraInit = 1;
#endif
}
sqlite3GlobalConfig.inProgress = 0;
|
| ︙ | ︙ | |||
183394 183395 183396 183397 183398 183399 183400 183401 183402 183403 183404 183405 183406 183407 | if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xBusyHandler = xBusy; db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* ** This routine sets the progress callback for an Sqlite database to the | > > > | 184073 184074 184075 184076 184077 184078 184079 184080 184081 184082 184083 184084 184085 184086 184087 184088 184089 | if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); db->busyHandler.xBusyHandler = xBusy; db->busyHandler.pBusyArg = pArg; db->busyHandler.nBusy = 0; db->busyTimeout = 0; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT db->setlkTimeout = 0; #endif sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK /* ** This routine sets the progress callback for an Sqlite database to the |
| ︙ | ︙ | |||
183443 183444 183445 183446 183447 183448 183449 183450 183451 183452 183453 183454 183455 183456 183457 183458 183459 183460 183461 |
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
}else{
sqlite3_busy_handler(db, 0, 0);
}
return SQLITE_OK;
}
/*
** Cause any pending operation to stop at its earliest opportunity.
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db)
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 184125 184126 184127 184128 184129 184130 184131 184132 184133 184134 184135 184136 184137 184138 184139 184140 184141 184142 184143 184144 184145 184146 184147 184148 184149 184150 184151 184152 184153 184154 184155 184156 184157 184158 184159 184160 184161 184162 184163 184164 184165 184166 184167 184168 184169 184170 184171 184172 184173 184174 184175 184176 184177 184178 |
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms>0 ){
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
(void*)db);
db->busyTimeout = ms;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
db->setlkTimeout = ms;
#endif
}else{
sqlite3_busy_handler(db, 0, 0);
}
return SQLITE_OK;
}
/*
** Set the setlk timeout value.
*/
SQLITE_API int sqlite3_setlk_timeout(sqlite3 *db, int ms, int flags){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int iDb;
int bBOC = ((flags & SQLITE_SETLK_BLOCK_ON_CONNECT) ? 1 : 0);
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
#endif
if( ms<-1 ) return SQLITE_RANGE;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
db->setlkTimeout = ms;
db->setlkFlags = flags;
sqlite3BtreeEnterAll(db);
for(iDb=0; iDb<db->nDb; iDb++){
Btree *pBt = db->aDb[iDb].pBt;
if( pBt ){
sqlite3_file *fd = sqlite3PagerFile(sqlite3BtreePager(pBt));
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_BLOCK_ON_CONNECT, (void*)&bBOC);
}
}
sqlite3BtreeLeaveAll(db);
#endif
#if !defined(SQLITE_ENABLE_API_ARMOR) && !defined(SQLITE_ENABLE_SETLK_TIMEOUT)
UNUSED_PARAMETER(db);
UNUSED_PARAMETER(flags);
#endif
return SQLITE_OK;
}
/*
** Cause any pending operation to stop at its earliest opportunity.
*/
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db)
|
| ︙ | ︙ | |||
185414 185415 185416 185417 185418 185419 185420 |
return SQLITE_OK;
}
}else if( pData==0 ){
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}else{
size_t n = strlen(zName);
| | | 186131 186132 186133 186134 186135 186136 186137 186138 186139 186140 186141 186142 186143 186144 186145 |
return SQLITE_OK;
}
}else if( pData==0 ){
sqlite3_mutex_leave(db->mutex);
return SQLITE_OK;
}else{
size_t n = strlen(zName);
p = sqlite3_malloc64( SZ_DBCLIENTDATA(n+1) );
if( p==0 ){
if( xDestructor ) xDestructor(pData);
sqlite3_mutex_leave(db->mutex);
return SQLITE_NOMEM;
}
memcpy(p->zName, zName, n+1);
p->pNext = db->pDbData;
|
| ︙ | ︙ | |||
185780 185781 185782 185783 185784 185785 185786 |
break;
}
#endif
/* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
**
** If b is true, then activate the SQLITE_FkNoAction setting. If b is
| | | | 186497 186498 186499 186500 186501 186502 186503 186504 186505 186506 186507 186508 186509 186510 186511 186512 |
break;
}
#endif
/* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
**
** If b is true, then activate the SQLITE_FkNoAction setting. If b is
** false then clear that setting. If the SQLITE_FkNoAction setting is
** enabled, all foreign key ON DELETE and ON UPDATE actions behave as if
** they were NO ACTION, regardless of how they are defined.
**
** NB: One must usually run "PRAGMA writable_schema=RESET" after
** using this test-control, before it will take full effect. failing
** to reset the schema can result in some unexpected behavior.
*/
case SQLITE_TESTCTRL_FK_NO_ACTION: {
|
| ︙ | ︙ | |||
187128 187129 187130 187131 187132 187133 187134 |
** }
** varint POS_END; (marks end of positions for this document.
** }
**
** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream
** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
| | | 187845 187846 187847 187848 187849 187850 187851 187852 187853 187854 187855 187856 187857 187858 187859 |
** }
** varint POS_END; (marks end of positions for this document.
** }
**
** Here, array { X } means zero or more occurrences of X, adjacent in
** memory. A "position" is an index of a token in the token stream
** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
** in the same logical place as the position element, and act as sentinels
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
** The positions numbers are not stored literally but rather as two more
** than the difference from the prior position, or the just the position plus
** 2 for the first position. Example:
**
** label: A B C D E F G H I J K
** value: 123 5 9 1 1 14 35 0 234 72 0
|
| ︙ | ︙ | |||
187815 187816 187817 187818 187819 187820 187821 187822 187823 187824 187825 187826 187827 187828 | # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) #define deliberate_fall_through #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else | > > > > > > > > > > > > > | 188532 188533 188534 188535 188536 188537 188538 188539 188540 188541 188542 188543 188544 188545 188546 188547 188548 188549 188550 188551 188552 188553 188554 188555 188556 188557 188558 | # define TESTONLY(X) #endif #define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) #define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) #define deliberate_fall_through /* ** Macros needed to provide flexible arrays in a portable way */ #ifndef offsetof # define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define FLEXARRAY #else # define FLEXARRAY 1 #endif #endif /* SQLITE_AMALGAMATION */ #ifdef SQLITE_DEBUG SQLITE_PRIVATE int sqlite3Fts3Corrupt(void); # define FTS_CORRUPT_VTAB sqlite3Fts3Corrupt() #else |
| ︙ | ︙ | |||
187920 187921 187922 187923 187924 187925 187926 | ** verifying the operation of the SQLite core. */ int inTransaction; /* True after xBegin but before xCommit/xRollback */ int mxSavepoint; /* Largest valid xSavepoint integer */ #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) | | | 188650 188651 188652 188653 188654 188655 188656 188657 188658 188659 188660 188661 188662 188663 188664 | ** verifying the operation of the SQLite core. */ int inTransaction; /* True after xBegin but before xCommit/xRollback */ int mxSavepoint; /* Largest valid xSavepoint integer */ #endif #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* True to disable the incremental doclist optimization. This is controlled ** by special insert command 'test-no-incr-doclist'. */ int bNoIncrDoclist; /* Number of segments in a level */ int nMergeCount; #endif }; |
| ︙ | ︙ | |||
187972 187973 187974 187975 187976 187977 187978 | #define FTS3_EVAL_FILTER 0 #define FTS3_EVAL_NEXT 1 #define FTS3_EVAL_MATCHINFO 2 /* ** The Fts3Cursor.eSearch member is always set to one of the following. | | | 188702 188703 188704 188705 188706 188707 188708 188709 188710 188711 188712 188713 188714 188715 188716 | #define FTS3_EVAL_FILTER 0 #define FTS3_EVAL_NEXT 1 #define FTS3_EVAL_MATCHINFO 2 /* ** The Fts3Cursor.eSearch member is always set to one of the following. ** Actually, Fts3Cursor.eSearch can be greater than or equal to ** FTS3_FULLTEXT_SEARCH. If so, then Fts3Cursor.eSearch - 2 is the index ** of the column to be searched. For example, in ** ** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d); ** SELECT docid FROM ex1 WHERE b MATCH 'one two three'; ** ** Because the LHS of the MATCH operator is 2nd column "b", |
| ︙ | ︙ | |||
188045 188046 188047 188048 188049 188050 188051 | i64 iOrDocid; /* Variables below this point are populated by fts3_expr.c when parsing ** a MATCH expression. Everything above is part of the evaluation phase. */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ | | > > > > | 188775 188776 188777 188778 188779 188780 188781 188782 188783 188784 188785 188786 188787 188788 188789 188790 188791 188792 188793 188794 | i64 iOrDocid; /* Variables below this point are populated by fts3_expr.c when parsing ** a MATCH expression. Everything above is part of the evaluation phase. */ int nToken; /* Number of tokens in the phrase */ int iColumn; /* Index of column this phrase must match */ Fts3PhraseToken aToken[FLEXARRAY]; /* One for each token in the phrase */ }; /* Size (in bytes) of an Fts3Phrase object large enough to hold N tokens */ #define SZ_FTS3PHRASE(N) \ (offsetof(Fts3Phrase,aToken)+(N)*sizeof(Fts3PhraseToken)) /* ** A tree of these objects forms the RHS of a MATCH operator. ** ** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist ** points to a malloced buffer, size nDoclist bytes, containing the results ** of this phrase query in FTS3 doclist format. As usual, the initial |
| ︙ | ︙ | |||
190625 190626 190627 190628 190629 190630 190631 | ** be larger in the output than it was in the input (since the delta value ** may be a larger positive integer than the actual docid). ** ** The space required to store the output is therefore the sum of the ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** | | | 191359 191360 191361 191362 191363 191364 191365 191366 191367 191368 191369 191370 191371 191372 191373 | ** be larger in the output than it was in the input (since the delta value ** may be a larger positive integer than the actual docid). ** ** The space required to store the output is therefore the sum of the ** sizes of the two inputs, plus enough space for exactly one of the input ** docids to grow. ** ** A symmetric argument may be made if the doclists are in descending ** order. */ aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING); if( !aOut ) return SQLITE_NOMEM; p = aOut; fts3GetDeltaVarint3(&p1, pEnd1, 0, &i1); |
| ︙ | ︙ | |||
192723 192724 192725 192726 192727 192728 192729 | /* ** The phrase iterator passed as the second argument: ** ** * features at least one token that uses an incremental doclist, and ** ** * does not contain any deferred tokens. ** | | | 193457 193458 193459 193460 193461 193462 193463 193464 193465 193466 193467 193468 193469 193470 193471 | /* ** The phrase iterator passed as the second argument: ** ** * features at least one token that uses an incremental doclist, and ** ** * does not contain any deferred tokens. ** ** Advance it to the next matching document in the database and populate ** the Fts3Doclist.pList and nList fields. ** ** If there is no "next" entry and no error occurs, then *pbEof is set to ** 1 before returning. Otherwise, if no error occurs and the iterator is ** successfully advanced, *pbEof is set to 0. ** ** If an error occurs, return an SQLite error code. Otherwise, return |
| ︙ | ︙ | |||
193730 193731 193732 193733 193734 193735 193736 |
pCsr->isEof = 1;
}
return rc;
}
/*
| | | 194464 194465 194466 194467 194468 194469 194470 194471 194472 194473 194474 194475 194476 194477 194478 |
pCsr->isEof = 1;
}
return rc;
}
/*
** Restart iteration for expression pExpr so that the next call to
** fts3EvalNext() visits the first row. Do not allow incremental
** loading or merging of phrase doclists for this iteration.
**
** If *pRc is other than SQLITE_OK when this function is called, it is
** a no-op. If an error occurs within this function, *pRc is set to an
** SQLite error code before returning.
*/
|
| ︙ | ︙ | |||
194921 194922 194923 194924 194925 194926 194927 194928 194929 194930 194931 194932 194933 194934 | } /* ** Function getNextNode(), which is called by fts3ExprParse(), may itself ** call fts3ExprParse(). So this forward declaration is required. */ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *); /* ** Extract the next token from buffer z (length n) using the tokenizer ** and other information (column names etc.) in pParse. Create an Fts3Expr ** structure of type FTSQUERY_PHRASE containing a phrase consisting of this ** single token and set *ppExpr to point to it. If the end of the buffer is ** reached before a token is found, set *ppExpr to zero. It is the | > > > > > > > > > > > > > > > > > | 195655 195656 195657 195658 195659 195660 195661 195662 195663 195664 195665 195666 195667 195668 195669 195670 195671 195672 195673 195674 195675 195676 195677 195678 195679 195680 195681 195682 195683 195684 195685 |
}
/*
** Function getNextNode(), which is called by fts3ExprParse(), may itself
** call fts3ExprParse(). So this forward declaration is required.
*/
static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
/*
** Search buffer z[], size n, for a '"' character. Or, if enable_parenthesis
** is defined, search for '(' and ')' as well. Return the index of the first
** such character in the buffer. If there is no such character, return -1.
*/
static int findBarredChar(const char *z, int n){
int ii;
for(ii=0; ii<n; ii++){
if( (z[ii]=='"')
|| (sqlite3_fts3_enable_parentheses && (z[ii]=='(' || z[ii]==')'))
){
return ii;
}
}
return -1;
}
/*
** Extract the next token from buffer z (length n) using the tokenizer
** and other information (column names etc.) in pParse. Create an Fts3Expr
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
** single token and set *ppExpr to point to it. If the end of the buffer is
** reached before a token is found, set *ppExpr to zero. It is the
|
| ︙ | ︙ | |||
194946 194947 194948 194949 194950 194951 194952 |
int *pnConsumed /* OUT: Number of bytes consumed */
){
sqlite3_tokenizer *pTokenizer = pParse->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
| < < < < < < < | | > > > > > > > > > > > | | | 195697 195698 195699 195700 195701 195702 195703 195704 195705 195706 195707 195708 195709 195710 195711 195712 195713 195714 195715 195716 195717 195718 195719 195720 195721 195722 195723 195724 195725 195726 195727 195728 195729 195730 195731 195732 195733 195734 195735 195736 195737 195738 195739 195740 195741 195742 |
int *pnConsumed /* OUT: Number of bytes consumed */
){
sqlite3_tokenizer *pTokenizer = pParse->pTokenizer;
sqlite3_tokenizer_module const *pModule = pTokenizer->pModule;
int rc;
sqlite3_tokenizer_cursor *pCursor;
Fts3Expr *pRet = 0;
*pnConsumed = n;
rc = sqlite3Fts3OpenTokenizer(pTokenizer, pParse->iLangid, z, n, &pCursor);
if( rc==SQLITE_OK ){
const char *zToken;
int nToken = 0, iStart = 0, iEnd = 0, iPosition = 0;
sqlite3_int64 nByte; /* total space to allocate */
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
if( rc==SQLITE_OK ){
/* Check that this tokenization did not gobble up any " characters. Or,
** if enable_parenthesis is true, that it did not gobble up any
** open or close parenthesis characters either. If it did, call
** getNextToken() again, but pass only that part of the input buffer
** up to the first such character. */
int iBarred = findBarredChar(z, iEnd);
if( iBarred>=0 ){
pModule->xClose(pCursor);
return getNextToken(pParse, iCol, z, iBarred, ppExpr, pnConsumed);
}
nByte = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1) + nToken;
pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
if( !pRet ){
rc = SQLITE_NOMEM;
}else{
pRet->eType = FTSQUERY_PHRASE;
pRet->pPhrase = (Fts3Phrase *)&pRet[1];
pRet->pPhrase->nToken = 1;
pRet->pPhrase->iColumn = iCol;
pRet->pPhrase->aToken[0].n = nToken;
pRet->pPhrase->aToken[0].z = (char*)&pRet->pPhrase->aToken[1];
memcpy(pRet->pPhrase->aToken[0].z, zToken, nToken);
if( iEnd<n && z[iEnd]=='*' ){
pRet->pPhrase->aToken[0].isPrefix = 1;
iEnd++;
}
|
| ︙ | ︙ | |||
194997 194998 194999 195000 195001 195002 195003 |
}else{
break;
}
}
}
*pnConsumed = iEnd;
| | > > > > | 195752 195753 195754 195755 195756 195757 195758 195759 195760 195761 195762 195763 195764 195765 195766 195767 195768 195769 195770 |
}else{
break;
}
}
}
*pnConsumed = iEnd;
}else if( n && rc==SQLITE_DONE ){
int iBarred = findBarredChar(z, n);
if( iBarred>=0 ){
*pnConsumed = iBarred;
}
rc = SQLITE_OK;
}
pModule->xClose(pCursor);
}
*ppExpr = pRet;
|
| ︙ | ︙ | |||
195046 195047 195048 195049 195050 195051 195052 | sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; i64 nTemp = 0; | | | 195805 195806 195807 195808 195809 195810 195811 195812 195813 195814 195815 195816 195817 195818 195819 | sqlite3_tokenizer_module const *pModule = pTokenizer->pModule; int rc; Fts3Expr *p = 0; sqlite3_tokenizer_cursor *pCursor = 0; char *zTemp = 0; i64 nTemp = 0; const int nSpace = sizeof(Fts3Expr) + SZ_FTS3PHRASE(1); int nToken = 0; /* The final Fts3Expr data structure, including the Fts3Phrase, ** Fts3PhraseToken structures token buffers are all stored as a single ** allocation so that the expression can be freed with a single call to ** sqlite3_free(). Setting this up requires a two pass approach. ** |
| ︙ | ︙ | |||
195418 195419 195420 195421 195422 195423 195424 |
p = pPrev;
}else{
int eType = p->eType;
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
/* The isRequirePhrase variable is set to true if a phrase or
** an expression contained in parenthesis is required. If a
| | | 196177 196178 196179 196180 196181 196182 196183 196184 196185 196186 196187 196188 196189 196190 196191 |
p = pPrev;
}else{
int eType = p->eType;
isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);
/* The isRequirePhrase variable is set to true if a phrase or
** an expression contained in parenthesis is required. If a
** binary operator (AND, OR, NOT or NEAR) is encountered when
** isRequirePhrase is set, this is a syntax error.
*/
if( !isPhrase && isRequirePhrase ){
sqlite3Fts3ExprFree(p);
rc = SQLITE_ERROR;
goto exprparse_out;
}
|
| ︙ | ︙ | |||
196000 196001 196002 196003 196004 196005 196006 |
}else{
rc = fts3ExprParseUnbalanced(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
);
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
| < | 196759 196760 196761 196762 196763 196764 196765 196766 196767 196768 196769 196770 196771 196772 |
}else{
rc = fts3ExprParseUnbalanced(
pTokenizer, 0, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
);
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
sqlite3_result_error(context, "Error parsing expression", -1);
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
sqlite3_free(zBuf);
}
|
| ︙ | ︙ | |||
196243 196244 196245 196246 196247 196248 196249 |
pH->first = pNew;
}
pEntry->count++;
pEntry->chain = pNew;
}
| | | 197001 197002 197003 197004 197005 197006 197007 197008 197009 197010 197011 197012 197013 197014 197015 |
pH->first = pNew;
}
pEntry->count++;
pEntry->chain = pNew;
}
/* Resize the hash table so that it contains "new_size" buckets.
** "new_size" must be a power of 2. The hash table might fail
** to resize if sqliteMalloc() fails.
**
** Return non-zero if a memory allocation error occurs.
*/
static int fts3Rehash(Fts3Hash *pH, int new_size){
struct _fts3ht *new_ht; /* The new hash table */
|
| ︙ | ︙ | |||
196698 196699 196700 196701 196702 196703 196704 |
z[0]!='w' && z[0]!='x' && z[0]!='y' &&
isVowel(z+1) &&
isConsonant(z+2);
}
/*
** If the word ends with zFrom and xCond() is true for the stem
| | | 197456 197457 197458 197459 197460 197461 197462 197463 197464 197465 197466 197467 197468 197469 197470 |
z[0]!='w' && z[0]!='x' && z[0]!='y' &&
isVowel(z+1) &&
isConsonant(z+2);
}
/*
** If the word ends with zFrom and xCond() is true for the stem
** of the word that precedes the zFrom ending, then change the
** ending to zTo.
**
** The input word *pz and zFrom are both in reverse order. zTo
** is in normal order.
**
** Return TRUE if zFrom matches. Return FALSE if zFrom does not
** match. Not that TRUE is returned even if xCond() fails and
|
| ︙ | ︙ | |||
202281 202282 202283 202284 202285 202286 202287 | ** If the size of the value in blob pPrev is zero, then this is the first ** term written to the node. Otherwise, pPrev contains a copy of the ** previous term. Before this function returns, it is updated to contain a ** copy of zTerm/nTerm. ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev | | | 203039 203040 203041 203042 203043 203044 203045 203046 203047 203048 203049 203050 203051 203052 203053 | ** If the size of the value in blob pPrev is zero, then this is the first ** term written to the node. Otherwise, pPrev contains a copy of the ** previous term. Before this function returns, it is updated to contain a ** copy of zTerm/nTerm. ** ** It is assumed that the buffer associated with pNode is already large ** enough to accommodate the new entry. The buffer associated with pPrev ** is extended by this function if required. ** ** If an error (i.e. OOM condition) occurs, an SQLite error code is ** returned. Otherwise, SQLITE_OK. */ static int fts3AppendToNode( Blob *pNode, /* Current node image to append to */ Blob *pPrev, /* Buffer containing previous term written */ |
| ︙ | ︙ | |||
203944 203945 203946 203947 203948 203949 203950 | return SQLITE_OK; } #endif /* ** SQLite value pRowid contains the rowid of a row that may or may not be ** present in the FTS3 table. If it is, delete it and adjust the contents | | | 204702 204703 204704 204705 204706 204707 204708 204709 204710 204711 204712 204713 204714 204715 204716 |
return SQLITE_OK;
}
#endif
/*
** SQLite value pRowid contains the rowid of a row that may or may not be
** present in the FTS3 table. If it is, delete it and adjust the contents
** of subsidiary data structures accordingly.
*/
static int fts3DeleteByRowid(
Fts3Table *p,
sqlite3_value *pRowid,
int *pnChng, /* IN/OUT: Decrement if row is deleted */
u32 *aSzDel
){
|
| ︙ | ︙ | |||
204270 204271 204272 204273 204274 204275 204276 |
** for details.
*/
struct MatchinfoBuffer {
u8 aRef[3];
int nElem;
int bGlobal; /* Set if global data is loaded */
char *zMatchinfo;
| | > > > > | 205028 205029 205030 205031 205032 205033 205034 205035 205036 205037 205038 205039 205040 205041 205042 205043 205044 205045 205046 205047 |
** for details.
*/
struct MatchinfoBuffer {
u8 aRef[3];
int nElem;
int bGlobal; /* Set if global data is loaded */
char *zMatchinfo;
u32 aMI[FLEXARRAY];
};
/* Size (in bytes) of a MatchinfoBuffer sufficient for N elements */
#define SZ_MATCHINFOBUFFER(N) \
(offsetof(MatchinfoBuffer,aMI)+(((N)+1)/2)*sizeof(u64))
/*
** The snippet() and offsets() functions both return text values. An instance
** of the following structure is used to accumulate those values while the
** functions are running. See fts3StringAppend() for details.
*/
|
| ︙ | ︙ | |||
204297 204298 204299 204300 204301 204302 204303 |
/*
** Allocate a two-slot MatchinfoBuffer object.
*/
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
| | | | | | | | | | | | 205059 205060 205061 205062 205063 205064 205065 205066 205067 205068 205069 205070 205071 205072 205073 205074 205075 205076 205077 205078 205079 205080 205081 205082 205083 205084 205085 205086 205087 205088 205089 205090 205091 205092 205093 205094 205095 205096 205097 205098 205099 205100 205101 205102 205103 205104 205105 205106 205107 205108 205109 205110 205111 205112 205113 205114 205115 205116 205117 205118 205119 205120 205121 205122 205123 205124 205125 205126 205127 205128 205129 205130 205131 205132 205133 205134 |
/*
** Allocate a two-slot MatchinfoBuffer object.
*/
static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
MatchinfoBuffer *pRet;
sqlite3_int64 nByte = sizeof(u32) * (2*(sqlite3_int64)nElem + 1)
+ SZ_MATCHINFOBUFFER(1);
sqlite3_int64 nStr = strlen(zMatchinfo);
pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
if( pRet ){
pRet->aMI[0] = (u8*)(&pRet->aMI[1]) - (u8*)pRet;
pRet->aMI[1+nElem] = pRet->aMI[0]
+ sizeof(u32)*((int)nElem+1);
pRet->nElem = (int)nElem;
pRet->zMatchinfo = ((char*)pRet) + nByte;
memcpy(pRet->zMatchinfo, zMatchinfo, nStr+1);
pRet->aRef[0] = 1;
}
return pRet;
}
static void fts3MIBufferFree(void *p){
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
assert( (u32*)p==&pBuf->aMI[1]
|| (u32*)p==&pBuf->aMI[pBuf->nElem+2]
);
if( (u32*)p==&pBuf->aMI[1] ){
pBuf->aRef[1] = 0;
}else{
pBuf->aRef[2] = 0;
}
if( pBuf->aRef[0]==0 && pBuf->aRef[1]==0 && pBuf->aRef[2]==0 ){
sqlite3_free(pBuf);
}
}
static void (*fts3MIBufferAlloc(MatchinfoBuffer *p, u32 **paOut))(void*){
void (*xRet)(void*) = 0;
u32 *aOut = 0;
if( p->aRef[1]==0 ){
p->aRef[1] = 1;
aOut = &p->aMI[1];
xRet = fts3MIBufferFree;
}
else if( p->aRef[2]==0 ){
p->aRef[2] = 1;
aOut = &p->aMI[p->nElem+2];
xRet = fts3MIBufferFree;
}else{
aOut = (u32*)sqlite3_malloc64(p->nElem * sizeof(u32));
if( aOut ){
xRet = sqlite3_free;
if( p->bGlobal ) memcpy(aOut, &p->aMI[1], p->nElem*sizeof(u32));
}
}
*paOut = aOut;
return xRet;
}
static void fts3MIBufferSetGlobal(MatchinfoBuffer *p){
p->bGlobal = 1;
memcpy(&p->aMI[2+p->nElem], &p->aMI[1], p->nElem*sizeof(u32));
}
/*
** Free a MatchinfoBuffer object allocated using fts3MIBufferNew()
*/
SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
if( p ){
|
| ︙ | ︙ | |||
204773 204774 204775 204776 204777 204778 204779 |
int nAppend /* Size of zAppend in bytes (or -1) */
){
if( nAppend<0 ){
nAppend = (int)strlen(zAppend);
}
/* If there is insufficient space allocated at StrBuffer.z, use realloc()
| | | 205535 205536 205537 205538 205539 205540 205541 205542 205543 205544 205545 205546 205547 205548 205549 |
int nAppend /* Size of zAppend in bytes (or -1) */
){
if( nAppend<0 ){
nAppend = (int)strlen(zAppend);
}
/* If there is insufficient space allocated at StrBuffer.z, use realloc()
** to grow the buffer until so that it is big enough to accommodate the
** appended data.
*/
if( pStr->n+nAppend+1>=pStr->nAlloc ){
sqlite3_int64 nAlloc = pStr->nAlloc+(sqlite3_int64)nAppend+100;
char *zNew = sqlite3_realloc64(pStr->z, nAlloc);
if( !zNew ){
return SQLITE_NOMEM;
|
| ︙ | ︙ | |||
207148 207149 207150 207151 207152 207153 207154 | ** Search for a cached translation the json text supplied by pArg. Return ** the JsonParse object if found. Return NULL if not found. ** ** When a match if found, the matching entry is moved to become the ** most-recently used entry if it isn't so already. ** ** The JsonParse object returned still belongs to the Cache and might | | | 207910 207911 207912 207913 207914 207915 207916 207917 207918 207919 207920 207921 207922 207923 207924 |
** Search for a cached translation the json text supplied by pArg. Return
** the JsonParse object if found. Return NULL if not found.
**
** When a match if found, the matching entry is moved to become the
** most-recently used entry if it isn't so already.
**
** The JsonParse object returned still belongs to the Cache and might
** be deleted at any moment. If the caller wants the JsonParse to
** linger, it needs to increment the nPJRef reference counter.
*/
static JsonParse *jsonCacheSearch(
sqlite3_context *ctx, /* The SQL statement context holding the cache */
sqlite3_value *pArg /* Function argument containing SQL text */
){
JsonCache *p;
|
| ︙ | ︙ | |||
210193 210194 210195 210196 210197 210198 210199 |
/* If the blob is not valid JSONB, fall through into trying to cast
** the blob into text which is then interpreted as JSON. (tag-20240123-a)
**
** This goes against all historical documentation about how the SQLite
** JSON functions were suppose to work. From the beginning, blob was
** reserved for expansion and a blob value should have raised an error.
** But it did not, due to a bug. And many applications came to depend
| | | 210955 210956 210957 210958 210959 210960 210961 210962 210963 210964 210965 210966 210967 210968 210969 |
/* If the blob is not valid JSONB, fall through into trying to cast
** the blob into text which is then interpreted as JSON. (tag-20240123-a)
**
** This goes against all historical documentation about how the SQLite
** JSON functions were suppose to work. From the beginning, blob was
** reserved for expansion and a blob value should have raised an error.
** But it did not, due to a bug. And many applications came to depend
** upon this buggy behavior, especially when using the CLI and reading
** JSON text using readfile(), which returns a blob. For this reason
** we will continue to support the bug moving forward.
** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
*/
}
p->zJson = (char*)sqlite3_value_text(pArg);
p->nJson = sqlite3_value_bytes(pArg);
|
| ︙ | ︙ | |||
212293 212294 212295 212296 212297 212298 212299 212300 212301 212302 212303 212304 212305 212306 | #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #endif /* !defined(SQLITE_AMALGAMATION) */ /* Macro to check for 4-byte alignment. Only used inside of assert() */ #ifdef SQLITE_DEBUG # define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0) #endif | > > > > > > > > | 213055 213056 213057 213058 213059 213060 213061 213062 213063 213064 213065 213066 213067 213068 213069 213070 213071 213072 213073 213074 213075 213076 | #elif !defined(NDEBUG) # define ALWAYS(X) ((X)?1:(assert(0),0)) # define NEVER(X) ((X)?(assert(0),1):0) #else # define ALWAYS(X) (X) # define NEVER(X) (X) #endif #ifndef offsetof #define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define FLEXARRAY #else # define FLEXARRAY 1 #endif #endif /* !defined(SQLITE_AMALGAMATION) */ /* Macro to check for 4-byte alignment. Only used inside of assert() */ #ifdef SQLITE_DEBUG # define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0) #endif |
| ︙ | ︙ | |||
212613 212614 212615 212616 212617 212618 212619 |
** operand to the MATCH operator of an R-Tree.
*/
struct RtreeMatchArg {
u32 iSize; /* Size of this object */
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
| | > > > > | 213383 213384 213385 213386 213387 213388 213389 213390 213391 213392 213393 213394 213395 213396 213397 213398 213399 213400 213401 213402 213403 |
** operand to the MATCH operator of an R-Tree.
*/
struct RtreeMatchArg {
u32 iSize; /* Size of this object */
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
RtreeDValue aParam[FLEXARRAY]; /* Values for parameters to the SQL function */
};
/* Size of an RtreeMatchArg object with N parameters */
#define SZ_RTREEMATCHARG(N) \
(offsetof(RtreeMatchArg,aParam)+(N)*sizeof(RtreeDValue))
#ifndef MAX
# define MAX(x,y) ((x) < (y) ? (y) : (x))
#endif
#ifndef MIN
# define MIN(x,y) ((x) > (y) ? (y) : (x))
#endif
|
| ︙ | ︙ | |||
214304 214305 214306 214307 214308 214309 214310 | pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; pIdxInfo->estimatedRows = nRow; return rc; } /* | | | 215078 215079 215080 215081 215082 215083 215084 215085 215086 215087 215088 215089 215090 215091 215092 |
pIdxInfo->estimatedCost = (double)6.0 * (double)nRow;
pIdxInfo->estimatedRows = nRow;
return rc;
}
/*
** Return the N-dimensional volume of the cell stored in *p.
*/
static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
RtreeDValue area = (RtreeDValue)1;
assert( pRtree->nDim>=1 && pRtree->nDim<=5 );
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
switch( pRtree->nDim ){
|
| ︙ | ︙ | |||
216070 216071 216072 216073 216074 216075 216076 | va_end(ap); return pRet; } /* ** The second and subsequent arguments to this function are a printf() ** style format string and arguments. This function formats the string and | | | 216844 216845 216846 216847 216848 216849 216850 216851 216852 216853 216854 216855 216856 216857 216858 |
va_end(ap);
return pRet;
}
/*
** The second and subsequent arguments to this function are a printf()
** style format string and arguments. This function formats the string and
** appends it to the report being accumulated in pCheck.
*/
static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
if( pCheck->rc==SQLITE_OK && pCheck->nErr<RTREE_CHECK_MAX_ERROR ){
char *z = sqlite3_vmprintf(zFmt, ap);
if( z==0 ){
|
| ︙ | ︙ | |||
217258 217259 217260 217261 217262 217263 217264 | } /* ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** | | | 218032 218033 218034 218035 218036 218037 218038 218039 218040 218041 218042 218043 218044 218045 218046 | } /* ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: ** ** +2 x0,y0 is on the line segment ** ** +1 x0,y0 is beneath line segment ** ** 0 x0,y0 is not on or beneath the line segment or the line segment ** is vertical and x0,y0 is not on the line segment ** ** The left-most coordinate min(x1,x2) is not considered to be part of |
| ︙ | ︙ | |||
217364 217365 217366 217367 217368 217369 217370 |
sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
}
}
sqlite3_free(p1);
sqlite3_free(p2);
}
| | | 218138 218139 218140 218141 218142 218143 218144 218145 218146 218147 218148 218149 218150 218151 218152 |
sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
}
}
sqlite3_free(p1);
sqlite3_free(p2);
}
/* Objects used by the overlap algorithm. */
typedef struct GeoEvent GeoEvent;
typedef struct GeoSegment GeoSegment;
typedef struct GeoOverlap GeoOverlap;
struct GeoEvent {
double x; /* X coordinate at which event occurs */
int eType; /* 0 for ADD, 1 for REMOVE */
GeoSegment *pSeg; /* The segment to be added or removed */
|
| ︙ | ︙ | |||
218411 218412 218413 218414 218415 218416 218417 |
*/
static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
RtreeMatchArg *pBlob;
sqlite3_int64 nBlob;
int memErr = 0;
| < | | 219185 219186 219187 219188 219189 219190 219191 219192 219193 219194 219195 219196 219197 219198 219199 |
*/
static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
RtreeMatchArg *pBlob;
sqlite3_int64 nBlob;
int memErr = 0;
nBlob = SZ_RTREEMATCHARG(nArg) + nArg*sizeof(sqlite3_value*);
pBlob = (RtreeMatchArg *)sqlite3_malloc64(nBlob);
if( !pBlob ){
sqlite3_result_error_nomem(ctx);
}else{
int i;
pBlob->iSize = nBlob;
pBlob->cb = pGeomCtx[0];
|
| ︙ | ︙ | |||
219507 219508 219509 219510 219511 219512 219513 | ** mobile device that is frequently rebooted. Even after the writer process ** has committed one or more sub-transactions, other database clients continue ** to read from the original database snapshot. In other words, partially ** applied transactions are not visible to other clients. ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction | | | 220280 220281 220282 220283 220284 220285 220286 220287 220288 220289 220290 220291 220292 220293 220294 | ** mobile device that is frequently rebooted. Even after the writer process ** has committed one or more sub-transactions, other database clients continue ** to read from the original database snapshot. In other words, partially ** applied transactions are not visible to other clients. ** ** "RBU" stands for "Resumable Bulk Update". As in a large database update ** transmitted via a wireless network to a mobile device. A transaction ** applied using this extension is hence referred to as an "RBU update". ** ** ** LIMITATIONS ** ** An "RBU update" transaction is subject to the following limitations: ** ** * The transaction must consist of INSERT, UPDATE and DELETE operations |
| ︙ | ︙ | |||
219804 219805 219806 219807 219808 219809 219810 | ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** | | | 220577 220578 220579 220580 220581 220582 220583 220584 220585 220586 220587 220588 220589 220590 220591 | ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. ** ** As with sqlite3rbu_open(), Zipvfs users should refer to the comment ** describing the sqlite3rbu_create_vfs() API function below for ** a description of the complications associated with using RBU with ** zipvfs databases. */ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState |
| ︙ | ︙ | |||
219900 219901 219902 219903 219904 219905 219906 | SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* ** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the | | | 220673 220674 220675 220676 220677 220678 220679 220680 220681 220682 220683 220684 220685 220686 220687 | SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* ** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the ** current state of the RBU update application to the RBU database. ** ** If an error has already occurred as part of an sqlite3rbu_step() ** or sqlite3rbu_open() call, or if one occurs within this function, an ** SQLite error code is returned. Additionally, if pzErrmsg is not NULL, ** *pzErrmsg may be set to point to a buffer containing a utf-8 formatted ** English language error message. It is the responsibility of the caller to ** eventually free any such buffer using sqlite3_free(). |
| ︙ | ︙ | |||
224826 224827 224828 224829 224830 224831 224832 |
static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
rbu_file *p = (rbu_file *)pFile;
int rc;
rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
/* If this is an RBU vacuum operation and this is the target database,
** pretend that it has at least one page. Otherwise, SQLite will not
| | | 225599 225600 225601 225602 225603 225604 225605 225606 225607 225608 225609 225610 225611 225612 225613 |
static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
rbu_file *p = (rbu_file *)pFile;
int rc;
rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
/* If this is an RBU vacuum operation and this is the target database,
** pretend that it has at least one page. Otherwise, SQLite will not
** check for the existence of a *-wal file. rbuVfsRead() contains
** similar logic. */
if( rc==SQLITE_OK && *pSize==0
&& p->pRbu && rbuIsVacuum(p->pRbu)
&& (p->openFlags & SQLITE_OPEN_MAIN_DB)
){
*pSize = 1024;
}
|
| ︙ | ︙ | |||
228056 228057 228058 228059 228060 228061 228062 | sqlite3_finalize(pStmt); return rc; } /* ** This function is called to initialize the SessionTable.nCol, azCol[] ** abPK[] and azDflt[] members of SessionTable object pTab. If these | | | 228829 228830 228831 228832 228833 228834 228835 228836 228837 228838 228839 228840 228841 228842 228843 | sqlite3_finalize(pStmt); return rc; } /* ** This function is called to initialize the SessionTable.nCol, azCol[] ** abPK[] and azDflt[] members of SessionTable object pTab. If these ** fields are already initialized, this function is a no-op. ** ** If an error occurs, an error code is stored in sqlite3_session.rc and ** non-zero returned. Or, if no error occurs but the table has no primary ** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to ** indicate that updates on this table should be ignored. SessionTable.abPK ** is set to NULL in this case. */ |
| ︙ | ︙ | |||
229879 229880 229881 229882 229883 229884 229885 |
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut, /* First argument for xOutput */
int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
void **ppChangeset /* OUT: Buffer containing changeset */
){
sqlite3 *db = pSession->db; /* Source database handle */
SessionTable *pTab; /* Used to iterate through attached tables */
| | | 230652 230653 230654 230655 230656 230657 230658 230659 230660 230661 230662 230663 230664 230665 230666 |
int (*xOutput)(void *pOut, const void *pData, int nData),
void *pOut, /* First argument for xOutput */
int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
void **ppChangeset /* OUT: Buffer containing changeset */
){
sqlite3 *db = pSession->db; /* Source database handle */
SessionTable *pTab; /* Used to iterate through attached tables */
SessionBuffer buf = {0,0,0}; /* Buffer in which to accumulate changeset */
int rc; /* Return code */
assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) );
assert( xOutput!=0 || (pnChangeset!=0 && ppChangeset!=0) );
/* Zero the output variables in case an error occurs. If this session
** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
|
| ︙ | ︙ | |||
234313 234314 234315 234316 234317 234318 234319 234320 234321 234322 234323 234324 234325 234326 | #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif #endif /* Truncate very long tokens to this many bytes. Hard limit is ** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset ** field that occurs at the start of each leaf page (see fts5_index.c). */ #define FTS5_MAX_TOKEN_SIZE 32768 | > > > > > > > > > > > > | 235086 235087 235088 235089 235090 235091 235092 235093 235094 235095 235096 235097 235098 235099 235100 235101 235102 235103 235104 235105 235106 235107 235108 235109 235110 235111 | #ifdef SQLITE_4_BYTE_ALIGNED_MALLOC # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0) #else # define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0) #endif /* ** Macros needed to provide flexible arrays in a portable way */ #ifndef offsetof # define offsetof(STRUCTURE,FIELD) ((size_t)((char*)&((STRUCTURE*)0)->FIELD)) #endif #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define FLEXARRAY #else # define FLEXARRAY 1 #endif #endif /* Truncate very long tokens to this many bytes. Hard limit is ** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset ** field that occurs at the start of each leaf page (see fts5_index.c). */ #define FTS5_MAX_TOKEN_SIZE 32768 |
| ︙ | ︙ | |||
234385 234386 234387 234388 234389 234390 234391 |
** then an object of the following type is used to record the set of columns.
** Each entry in the aiCol[] array is a column that may be matched.
**
** This object is used by fts5_expr.c and fts5_index.c.
*/
struct Fts5Colset {
int nCol;
| | | > | 235170 235171 235172 235173 235174 235175 235176 235177 235178 235179 235180 235181 235182 235183 235184 235185 235186 235187 235188 |
** then an object of the following type is used to record the set of columns.
** Each entry in the aiCol[] array is a column that may be matched.
**
** This object is used by fts5_expr.c and fts5_index.c.
*/
struct Fts5Colset {
int nCol;
int aiCol[FLEXARRAY];
};
/* Size (int bytes) of a complete Fts5Colset object with N columns. */
#define SZ_FTS5COLSET(N) (sizeof(i64)*((N+2)/2))
/**************************************************************************
** Interface to code in fts5_config.c. fts5_config.c contains contains code
** to parse the arguments passed to the CREATE VIRTUAL TABLE statement.
*/
typedef struct Fts5Config Fts5Config;
|
| ︙ | ︙ | |||
235217 235218 235219 235220 235221 235222 235223 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Driver template for the LEMON parser generator. ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text | | | 236003 236004 236005 236006 236007 236008 236009 236010 236011 236012 236013 236014 236015 236016 236017 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Driver template for the LEMON parser generator. ** ** The "lemon" program processes an LALR(1) input grammar file, then uses ** this template to construct a parser. The "lemon" program inserts text ** at each "%%" line. Also, any "P-a-r-s-e" identifier prefix (without the ** interstitial "-" characters) contained in this template is changed into ** the value of the %name directive from the grammar. Otherwise, the content ** of this template is copied straight through into the generate parser ** source file. ** ** The following is the concatenation of all %include directives from the ** input grammar file: |
| ︙ | ︙ | |||
237371 237372 237373 237374 237375 237376 237377 |
** IDF = log( (N - nHit + 0.5) / (nHit + 0.5) )
**
** where "N" is the total number of documents in the set and nHit
** is the number that contain at least one instance of the phrase
** under consideration.
**
** The problem with this is that if (N < 2*nHit), the IDF is
| | | 238157 238158 238159 238160 238161 238162 238163 238164 238165 238166 238167 238168 238169 238170 238171 |
** IDF = log( (N - nHit + 0.5) / (nHit + 0.5) )
**
** where "N" is the total number of documents in the set and nHit
** is the number that contain at least one instance of the phrase
** under consideration.
**
** The problem with this is that if (N < 2*nHit), the IDF is
** negative. Which is undesirable. So the minimum allowable IDF is
** (1e-6) - roughly the same as a term that appears in just over
** half of set of 5,000,000 documents. */
double idf = log( (nRow - nHit + 0.5) / (nHit + 0.5) );
if( idf<=0.0 ) idf = 1e-6;
p->aIDF[i] = idf;
}
}
|
| ︙ | ︙ | |||
237834 237835 237836 237837 237838 237839 237840 | ** Return true if character 't' may be part of an FTS5 bareword, or false ** otherwise. Characters that may be part of barewords: ** ** * All non-ASCII characters, ** * The 52 upper and lower case ASCII characters, and ** * The 10 integer ASCII characters. ** * The underscore character "_" (0x5F). | | | 238620 238621 238622 238623 238624 238625 238626 238627 238628 238629 238630 238631 238632 238633 238634 |
** Return true if character 't' may be part of an FTS5 bareword, or false
** otherwise. Characters that may be part of barewords:
**
** * All non-ASCII characters,
** * The 52 upper and lower case ASCII characters, and
** * The 10 integer ASCII characters.
** * The underscore character "_" (0x5F).
** * The unicode "substitute" character (0x1A).
*/
static int sqlite3Fts5IsBareword(char t){
u8 aBareword[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 .. 0x0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 0x10 .. 0x1F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 .. 0x2F */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 0x30 .. 0x3F */
|
| ︙ | ︙ | |||
239152 239153 239154 239155 239156 239157 239158 | i64 iRowid; /* Current rowid */ Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ | | > > > > | 239938 239939 239940 239941 239942 239943 239944 239945 239946 239947 239948 239949 239950 239951 239952 239953 239954 239955 239956 239957 | i64 iRowid; /* Current rowid */ Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */ /* Child nodes. For a NOT node, this array always contains 2 entries. For ** AND or OR nodes, it contains 2 or more entries. */ int nChild; /* Number of child nodes */ Fts5ExprNode *apChild[FLEXARRAY]; /* Array of child nodes */ }; /* Size (in bytes) of an Fts5ExprNode object that holds up to N children */ #define SZ_FTS5EXPRNODE(N) \ (offsetof(Fts5ExprNode,apChild) + (N)*sizeof(Fts5ExprNode*)) #define Fts5NodeIsString(p) ((p)->eType==FTS5_TERM || (p)->eType==FTS5_STRING) /* ** Invoke the xNext method of an Fts5ExprNode object. This macro should be ** used as if it has the same signature as the xNext() methods themselves. */ |
| ︙ | ︙ | |||
239185 239186 239187 239188 239189 239190 239191 |
** A phrase. One or more terms that must appear in a contiguous sequence
** within a document for it to match.
*/
struct Fts5ExprPhrase {
Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
Fts5Buffer poslist; /* Current position list */
int nTerm; /* Number of entries in aTerm[] */
| | > > > > | > > > | 239975 239976 239977 239978 239979 239980 239981 239982 239983 239984 239985 239986 239987 239988 239989 239990 239991 239992 239993 239994 239995 239996 239997 239998 239999 240000 240001 240002 240003 240004 240005 240006 240007 240008 240009 |
** A phrase. One or more terms that must appear in a contiguous sequence
** within a document for it to match.
*/
struct Fts5ExprPhrase {
Fts5ExprNode *pNode; /* FTS5_STRING node this phrase is part of */
Fts5Buffer poslist; /* Current position list */
int nTerm; /* Number of entries in aTerm[] */
Fts5ExprTerm aTerm[FLEXARRAY]; /* Terms that make up this phrase */
};
/* Size (in bytes) of an Fts5ExprPhrase object that holds up to N terms */
#define SZ_FTS5EXPRPHRASE(N) \
(offsetof(Fts5ExprPhrase,aTerm) + (N)*sizeof(Fts5ExprTerm))
/*
** One or more phrases that must appear within a certain token distance of
** each other within each matching document.
*/
struct Fts5ExprNearset {
int nNear; /* NEAR parameter */
Fts5Colset *pColset; /* Columns to search (NULL -> all columns) */
int nPhrase; /* Number of entries in aPhrase[] array */
Fts5ExprPhrase *apPhrase[FLEXARRAY]; /* Array of phrase pointers */
};
/* Size (in bytes) of an Fts5ExprNearset object covering up to N phrases */
#define SZ_FTS5EXPRNEARSET(N) \
(offsetof(Fts5ExprNearset,apPhrase)+(N)*sizeof(Fts5ExprPhrase*))
/*
** Parse context.
*/
struct Fts5Parse {
Fts5Config *pConfig;
char *zErr;
|
| ︙ | ︙ | |||
239358 239359 239360 239361 239362 239363 239364 |
assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
| | | 240155 240156 240157 240158 240159 240160 240161 240162 240163 240164 240165 240166 240167 240168 240169 |
assert( sParse.pExpr || sParse.rc!=SQLITE_OK );
assert_expr_depth_ok(sParse.rc, sParse.pExpr);
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){
int n = SZ_FTS5COLSET(1);
Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n);
if( pColset ){
pColset->nCol = 1;
pColset->aiCol[0] = iCol;
sqlite3Fts5ParseSetColset(&sParse, sParse.pExpr, pColset);
}
}
|
| ︙ | ︙ | |||
240716 240717 240718 240719 240720 240721 240722 |
){
const int SZALLOC = 8;
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
if( pNear==0 ){
sqlite3_int64 nByte;
| | | | 241513 241514 241515 241516 241517 241518 241519 241520 241521 241522 241523 241524 241525 241526 241527 241528 241529 241530 241531 241532 241533 241534 241535 241536 241537 241538 |
){
const int SZALLOC = 8;
Fts5ExprNearset *pRet = 0;
if( pParse->rc==SQLITE_OK ){
if( pNear==0 ){
sqlite3_int64 nByte;
nByte = SZ_FTS5EXPRNEARSET(SZALLOC+1);
pRet = sqlite3_malloc64(nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
memset(pRet, 0, (size_t)nByte);
}
}else if( (pNear->nPhrase % SZALLOC)==0 ){
int nNew = pNear->nPhrase + SZALLOC;
sqlite3_int64 nByte;
nByte = SZ_FTS5EXPRNEARSET(nNew+1);
pRet = (Fts5ExprNearset*)sqlite3_realloc64(pNear, nByte);
if( pRet==0 ){
pParse->rc = SQLITE_NOMEM;
}
}else{
pRet = pNear;
}
|
| ︙ | ︙ | |||
240818 240819 240820 240821 240822 240823 240824 |
}else{
Fts5ExprTerm *pTerm;
if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){
Fts5ExprPhrase *pNew;
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
| | | | 241615 241616 241617 241618 241619 241620 241621 241622 241623 241624 241625 241626 241627 241628 241629 241630 241631 241632 241633 241634 |
}else{
Fts5ExprTerm *pTerm;
if( pPhrase==0 || (pPhrase->nTerm % SZALLOC)==0 ){
Fts5ExprPhrase *pNew;
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
SZ_FTS5EXPRPHRASE(nNew+1)
);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
if( pPhrase==0 ) memset(pNew, 0, SZ_FTS5EXPRPHRASE(1));
pCtx->pPhrase = pPhrase = pNew;
pNew->nTerm = nNew - SZALLOC;
}
}
if( rc==SQLITE_OK ){
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
|
| ︙ | ︙ | |||
240931 240932 240933 240934 240935 240936 240937 |
}
pParse->nPhrase++;
}
if( sCtx.pPhrase==0 ){
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
| | | 241728 241729 241730 241731 241732 241733 241734 241735 241736 241737 241738 241739 241740 241741 241742 |
}
pParse->nPhrase++;
}
if( sCtx.pPhrase==0 ){
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
sCtx.pPhrase = sqlite3Fts5MallocZero(&pParse->rc, SZ_FTS5EXPRPHRASE(1));
}else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
}
assert( pParse->apPhrase!=0 );
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
}
|
| ︙ | ︙ | |||
240966 240967 240968 240969 240970 240971 240972 |
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
}
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
| | < | | | 241763 241764 241765 241766 241767 241768 241769 241770 241771 241772 241773 241774 241775 241776 241777 241778 241779 241780 241781 241782 241783 241784 241785 241786 241787 241788 |
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
}
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
}
if( rc==SQLITE_OK ){
pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRNODE(1));
}
if( rc==SQLITE_OK ){
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
SZ_FTS5EXPRNEARSET(2));
}
if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlite3_int64 nByte;
Fts5Colset *pColset;
nByte = SZ_FTS5COLSET(pColsetOrig->nCol);
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
if( pColset ){
memcpy(pColset, pColsetOrig, (size_t)nByte);
}
pNew->pRoot->pNear->pColset = pColset;
}
}
|
| ︙ | ︙ | |||
241006 241007 241008 241009 241010 241011 241012 |
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
}
}
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
| | | 241802 241803 241804 241805 241806 241807 241808 241809 241810 241811 241812 241813 241814 241815 241816 |
sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
}
}
}else{
/* This happens when parsing a token or quoted phrase that contains
** no token characters at all. (e.g ... MATCH '""'). */
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, SZ_FTS5EXPRPHRASE(1));
}
}
if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
/* All the allocations succeeded. Put the expression object together. */
pNew->pIndex = pExpr->pIndex;
pNew->pConfig = pExpr->pConfig;
|
| ︙ | ︙ | |||
241100 241101 241102 241103 241104 241105 241106 |
){
int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */
Fts5Colset *pNew; /* New colset object to return */
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
| | | 241896 241897 241898 241899 241900 241901 241902 241903 241904 241905 241906 241907 241908 241909 241910 |
){
int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */
Fts5Colset *pNew; /* New colset object to return */
assert( pParse->rc==SQLITE_OK );
assert( iCol>=0 && iCol<pParse->pConfig->nCol );
pNew = sqlite3_realloc64(p, SZ_FTS5COLSET(nCol+1));
if( pNew==0 ){
pParse->rc = SQLITE_NOMEM;
}else{
int *aiCol = pNew->aiCol;
int i, j;
for(i=0; i<nCol; i++){
if( aiCol[i]==iCol ) return pNew;
|
| ︙ | ︙ | |||
241135 241136 241137 241138 241139 241140 241141 |
** as the second argument before returning.
*/
static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
Fts5Colset *pRet;
int nCol = pParse->pConfig->nCol;
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
| | | 241931 241932 241933 241934 241935 241936 241937 241938 241939 241940 241941 241942 241943 241944 241945 |
** as the second argument before returning.
*/
static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p){
Fts5Colset *pRet;
int nCol = pParse->pConfig->nCol;
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
SZ_FTS5COLSET(nCol+1)
);
if( pRet ){
int i;
int iOld = 0;
for(i=0; i<nCol; i++){
if( iOld>=p->nCol || p->aiCol[iOld]!=i ){
pRet->aiCol[pRet->nCol++] = i;
|
| ︙ | ︙ | |||
241196 241197 241198 241199 241200 241201 241202 |
** Otherwise, a copy of (*pOrig) is made into memory obtained from
** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
*/
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
Fts5Colset *pRet;
if( pOrig ){
| | | 241992 241993 241994 241995 241996 241997 241998 241999 242000 242001 242002 242003 242004 242005 242006 |
** Otherwise, a copy of (*pOrig) is made into memory obtained from
** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
** fails, (*pRc) is set to SQLITE_NOMEM and NULL is returned.
*/
static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
Fts5Colset *pRet;
if( pOrig ){
sqlite3_int64 nByte = SZ_FTS5COLSET(pOrig->nCol);
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
if( pRet ){
memcpy(pRet, pOrig, (size_t)nByte);
}
}else{
pRet = 0;
}
|
| ︙ | ︙ | |||
241364 241365 241366 241367 241368 241369 241370 | int ii; int nByte; Fts5ExprNode *pRet; assert( pNear->nPhrase==1 ); assert( pParse->bPhraseToAnd ); | | | | 242160 242161 242162 242163 242164 242165 242166 242167 242168 242169 242170 242171 242172 242173 242174 242175 242176 242177 242178 242179 242180 242181 242182 242183 242184 |
int ii;
int nByte;
Fts5ExprNode *pRet;
assert( pNear->nPhrase==1 );
assert( pParse->bPhraseToAnd );
nByte = SZ_FTS5EXPRNODE(nTerm+1);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
&pParse->rc, SZ_FTS5EXPRPHRASE(1)
);
if( pPhrase ){
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
|
| ︙ | ︙ | |||
241443 241444 241445 241446 241447 241448 241449 |
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
| | | 242239 242240 242241 242242 242243 242244 242245 242246 242247 242248 242249 242250 242251 242252 242253 |
nChild = 2;
}else if( eType==FTS5_AND || eType==FTS5_OR ){
nChild = 2;
if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
if( pRight->eType==eType ) nChild += pRight->nChild-1;
}
nByte = SZ_FTS5EXPRNODE(nChild);
pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
if( pRet ){
pRet->eType = eType;
pRet->pNear = pNear;
fts5ExprAssignXNext(pRet);
if( eType==FTS5_STRING ){
|
| ︙ | ︙ | |||
242318 242319 242320 242321 242322 242323 242324 |
*ppOut = pTerm->pTerm;
*pnOut = pTerm->nFullTerm;
}
return rc;
}
/*
| | | 243114 243115 243116 243117 243118 243119 243120 243121 243122 243123 243124 243125 243126 243127 243128 |
*ppOut = pTerm->pTerm;
*pnOut = pTerm->nFullTerm;
}
return rc;
}
/*
** Clear the token mappings for all Fts5IndexIter objects managed by
** the expression passed as the only argument.
*/
static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
int ii;
for(ii=0; ii<pExpr->nPhrase; ii++){
Fts5ExprTerm *pT;
for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
|
| ︙ | ︙ | |||
242353 242354 242355 242356 242357 242358 242359 | /* #include "fts5Int.h" */ typedef struct Fts5HashEntry Fts5HashEntry; /* ** This file contains the implementation of an in-memory hash table used | | | 243149 243150 243151 243152 243153 243154 243155 243156 243157 243158 243159 243160 243161 243162 243163 |
/* #include "fts5Int.h" */
typedef struct Fts5HashEntry Fts5HashEntry;
/*
** This file contains the implementation of an in-memory hash table used
** to accumulate "term -> doclist" content before it is flushed to a level-0
** segment.
*/
struct Fts5Hash {
int eDetail; /* Copy of Fts5Config.eDetail */
int *pnByte; /* Pointer to bytes counter */
|
| ︙ | ︙ | |||
242410 242411 242412 242413 242414 242415 242416 | u8 bContent; /* Set content-flag (detail=none mode) */ i16 iCol; /* Column of last value written */ int iPos; /* Position of last value written */ i64 iRowid; /* Rowid of last value written */ }; /* | | | 243206 243207 243208 243209 243210 243211 243212 243213 243214 243215 243216 243217 243218 243219 243220 |
u8 bContent; /* Set content-flag (detail=none mode) */
i16 iCol; /* Column of last value written */
int iPos; /* Position of last value written */
i64 iRowid; /* Rowid of last value written */
};
/*
** Equivalent to:
**
** char *fts5EntryKey(Fts5HashEntry *pEntry){ return zKey; }
*/
#define fts5EntryKey(p) ( ((char *)(&(p)[1])) )
/*
|
| ︙ | ︙ | |||
243346 243347 243348 243349 243350 243351 243352 |
};
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
| | > > > > | 244142 244143 244144 244145 244146 244147 244148 244149 244150 244151 244152 244153 244154 244155 244156 244157 244158 244159 244160 244161 244162 |
};
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
Fts5StructureLevel aLevel[FLEXARRAY]; /* Array of nLevel level objects */
};
/* Size (in bytes) of an Fts5Structure object holding up to N levels */
#define SZ_FTS5STRUCTURE(N) \
(offsetof(Fts5Structure,aLevel) + (N)*sizeof(Fts5StructureLevel))
/*
** An object of type Fts5SegWriter is used to write to segments.
*/
struct Fts5PageWriter {
int pgno; /* Page number for this page */
int iPrevPgidx; /* Previous value written into pgidx */
Fts5Buffer buf; /* Buffer containing leaf data */
|
| ︙ | ︙ | |||
243478 243479 243480 243481 243482 243483 243484 |
u8 bDel; /* True if the delete flag is set */
};
/*
** Array of tombstone pages. Reference counted.
*/
struct Fts5TombstoneArray {
| | | > > > > | 244278 244279 244280 244281 244282 244283 244284 244285 244286 244287 244288 244289 244290 244291 244292 244293 244294 244295 244296 244297 244298 244299 |
u8 bDel; /* True if the delete flag is set */
};
/*
** Array of tombstone pages. Reference counted.
*/
struct Fts5TombstoneArray {
int nRef; /* Number of pointers to this object */
int nTombstone;
Fts5Data *apTombstone[FLEXARRAY]; /* Array of tombstone pages */
};
/* Size (in bytes) of an Fts5TombstoneArray holding up to N tombstones */
#define SZ_FTS5TOMBSTONEARRAY(N) \
(offsetof(Fts5TombstoneArray,apTombstone)+(N)*sizeof(Fts5Data*))
/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
*/
#define ASSERT_SZLEAF_OK(x) assert( \
(x)->szLeaf==(x)->nn || (x)->szLeaf==fts5GetU16(&(x)->p[2]) \
|
| ︙ | ︙ | |||
243551 243552 243553 243554 243555 243556 243557 | int nSeg; /* Size of aSeg[] array */ int bRev; /* True to iterate in reverse order */ u8 bSkipEmpty; /* True to skip deleted entries */ i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ | | > > > | 244355 244356 244357 244358 244359 244360 244361 244362 244363 244364 244365 244366 244367 244368 244369 244370 244371 244372 244373 | int nSeg; /* Size of aSeg[] array */ int bRev; /* True to iterate in reverse order */ u8 bSkipEmpty; /* True to skip deleted entries */ i64 iSwitchRowid; /* Firstest rowid of other than aFirst[1] */ Fts5CResult *aFirst; /* Current merge state (see above) */ Fts5SegIter aSeg[FLEXARRAY]; /* Array of segment iterators */ }; /* Size (in bytes) of an Fts5Iter object holding up to N segment iterators */ #define SZ_FTS5ITER(N) (offsetof(Fts5Iter,aSeg)+(N)*sizeof(Fts5SegIter)) /* ** An instance of the following type is used to iterate through the contents ** of a doclist-index record. ** ** pData: ** Record containing the doclist-index data. |
| ︙ | ︙ | |||
243580 243581 243582 243583 243584 243585 243586 |
/* Output variables */
int iLeafPgno; /* Page number of current leaf page */
i64 iRowid; /* First rowid on leaf iLeafPgno */
};
struct Fts5DlidxIter {
int nLvl;
int iSegid;
| | > > > > | 244387 244388 244389 244390 244391 244392 244393 244394 244395 244396 244397 244398 244399 244400 244401 244402 244403 244404 244405 244406 |
/* Output variables */
int iLeafPgno; /* Page number of current leaf page */
i64 iRowid; /* First rowid on leaf iLeafPgno */
};
struct Fts5DlidxIter {
int nLvl;
int iSegid;
Fts5DlidxLvl aLvl[FLEXARRAY];
};
/* Size (in bytes) of an Fts5DlidxIter object with up to N levels */
#define SZ_FTS5DLIDXITER(N) \
(offsetof(Fts5DlidxIter,aLvl)+(N)*sizeof(Fts5DlidxLvl))
static void fts5PutU16(u8 *aOut, u16 iVal){
aOut[0] = (iVal>>8);
aOut[1] = (iVal&0xFF);
}
static u16 fts5GetU16(const u8 *aIn){
|
| ︙ | ︙ | |||
243950 243951 243952 243953 243954 243955 243956 |
**
** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If
** an error occurs, (*pRc) is set to an SQLite error code before returning.
*/
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
Fts5Structure *p = *pp;
if( *pRc==SQLITE_OK && p->nRef>1 ){
| | | 244761 244762 244763 244764 244765 244766 244767 244768 244769 244770 244771 244772 244773 244774 244775 |
**
** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If
** an error occurs, (*pRc) is set to an SQLite error code before returning.
*/
static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
Fts5Structure *p = *pp;
if( *pRc==SQLITE_OK && p->nRef>1 ){
i64 nByte = SZ_FTS5STRUCTURE(p->nLevel);
Fts5Structure *pNew;
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
if( pNew ){
int i;
memcpy(pNew, p, nByte);
for(i=0; i<p->nLevel; i++) pNew->aLevel[i].aSeg = 0;
for(i=0; i<p->nLevel; i++){
|
| ︙ | ︙ | |||
244024 244025 244026 244027 244028 244029 244030 |
i += fts5GetVarint32(&pData[i], nLevel);
i += fts5GetVarint32(&pData[i], nSegment);
if( nLevel>FTS5_MAX_SEGMENT || nLevel<0
|| nSegment>FTS5_MAX_SEGMENT || nSegment<0
){
return FTS5_CORRUPT;
}
| | < < < | 244835 244836 244837 244838 244839 244840 244841 244842 244843 244844 244845 244846 244847 244848 244849 |
i += fts5GetVarint32(&pData[i], nLevel);
i += fts5GetVarint32(&pData[i], nSegment);
if( nLevel>FTS5_MAX_SEGMENT || nLevel<0
|| nSegment>FTS5_MAX_SEGMENT || nSegment<0
){
return FTS5_CORRUPT;
}
nByte = SZ_FTS5STRUCTURE(nLevel);
pRet = (Fts5Structure*)sqlite3Fts5MallocZero(&rc, nByte);
if( pRet ){
pRet->nRef = 1;
pRet->nLevel = nLevel;
pRet->nSegment = nSegment;
i += sqlite3Fts5GetVarint(&pData[i], &pRet->nWriteCounter);
|
| ︙ | ︙ | |||
244107 244108 244109 244110 244111 244112 244113 |
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
| | < < < | 244915 244916 244917 244918 244919 244920 244921 244922 244923 244924 244925 244926 244927 244928 244929 |
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
sqlite3_int64 nByte = SZ_FTS5STRUCTURE(nLevel+2);
pStruct = sqlite3_realloc64(pStruct, nByte);
if( pStruct ){
memset(&pStruct->aLevel[nLevel], 0, sizeof(Fts5StructureLevel));
pStruct->nLevel++;
*ppStruct = pStruct;
}else{
|
| ︙ | ︙ | |||
244649 244650 244651 244652 244653 244654 244655 |
int iLeafPg /* Leaf page number to load dlidx for */
){
Fts5DlidxIter *pIter = 0;
int i;
int bDone = 0;
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
| | | 245454 245455 245456 245457 245458 245459 245460 245461 245462 245463 245464 245465 245466 245467 245468 |
int iLeafPg /* Leaf page number to load dlidx for */
){
Fts5DlidxIter *pIter = 0;
int i;
int bDone = 0;
for(i=0; p->rc==SQLITE_OK && bDone==0; i++){
sqlite3_int64 nByte = SZ_FTS5DLIDXITER(i+1);
Fts5DlidxIter *pNew;
pNew = (Fts5DlidxIter*)sqlite3_realloc64(pIter, nByte);
if( pNew==0 ){
p->rc = SQLITE_NOMEM;
}else{
i64 iRowid = FTS5_DLIDX_ROWID(iSegid, i, iLeafPg);
|
| ︙ | ︙ | |||
244867 244868 244869 244870 244871 244872 244873 |
** Allocate a tombstone hash page array object (pIter->pTombArray) for
** the iterator passed as the second argument. If an OOM error occurs,
** leave an error in the Fts5Index object.
*/
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
| | | 245672 245673 245674 245675 245676 245677 245678 245679 245680 245681 245682 245683 245684 245685 245686 |
** Allocate a tombstone hash page array object (pIter->pTombArray) for
** the iterator passed as the second argument. If an OOM error occurs,
** leave an error in the Fts5Index object.
*/
static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
const int nTomb = pIter->pSeg->nPgTombstone;
if( nTomb>0 ){
int nByte = SZ_FTS5TOMBSTONEARRAY(nTomb+1);
Fts5TombstoneArray *pNew;
pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
pNew->nTombstone = nTomb;
pNew->nRef = 1;
pIter->pTombArray = pNew;
}
|
| ︙ | ︙ | |||
246328 246329 246330 246331 246332 246333 246334 |
int nSeg
){
Fts5Iter *pNew;
i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
| | < | 247133 247134 247135 247136 247137 247138 247139 247140 247141 247142 247143 247144 247145 247146 247147 |
int nSeg
){
Fts5Iter *pNew;
i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
SZ_FTS5ITER(nSlot) + /* pNew + pNew->aSeg[] */
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
);
if( pNew ){
pNew->nSeg = nSlot;
pNew->aFirst = (Fts5CResult*)&pNew->aSeg[nSlot];
pNew->pIndex = p;
pNew->xSetOutputs = fts5IterSetOutputs_Noop;
|
| ︙ | ︙ | |||
248695 248696 248697 248698 248699 248700 248701 |
}
static Fts5Structure *fts5IndexOptimizeStruct(
Fts5Index *p,
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
| | | 249499 249500 249501 249502 249503 249504 249505 249506 249507 249508 249509 249510 249511 249512 249513 |
}
static Fts5Structure *fts5IndexOptimizeStruct(
Fts5Index *p,
Fts5Structure *pStruct
){
Fts5Structure *pNew = 0;
sqlite3_int64 nByte = SZ_FTS5STRUCTURE(1);
int nSeg = pStruct->nSegment;
int i;
/* Figure out if this structure requires optimization. A structure does
** not require optimization if either:
**
** 1. it consists of fewer than two segments, or
|
| ︙ | ︙ | |||
248725 248726 248727 248728 248729 248730 248731 248732 248733 248734 248735 248736 248737 248738 |
fts5StructureRef(pStruct);
return pStruct;
}
assert( pStruct->aLevel[i].nMerge<=nThis );
}
nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
Fts5StructureLevel *pLvl;
nByte = nSeg * sizeof(Fts5StructureSegment);
pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
| > | 249529 249530 249531 249532 249533 249534 249535 249536 249537 249538 249539 249540 249541 249542 249543 |
fts5StructureRef(pStruct);
return pStruct;
}
assert( pStruct->aLevel[i].nMerge<=nThis );
}
nByte += (((i64)pStruct->nLevel)+1) * sizeof(Fts5StructureLevel);
assert( nByte==SZ_FTS5STRUCTURE(pStruct->nLevel+2) );
pNew = (Fts5Structure*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pNew ){
Fts5StructureLevel *pLvl;
nByte = nSeg * sizeof(Fts5StructureSegment);
pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
|
| ︙ | ︙ | |||
249301 249302 249303 249304 249305 249306 249307 | Fts5Buffer terms; /* The following are used for other full-token tokendata queries only. */ int nIter; int nIterAlloc; Fts5PoslistReader *aPoslistReader; int *aPoslistToIter; | | > > > > | 250106 250107 250108 250109 250110 250111 250112 250113 250114 250115 250116 250117 250118 250119 250120 250121 250122 250123 250124 250125 |
Fts5Buffer terms;
/* The following are used for other full-token tokendata queries only. */
int nIter;
int nIterAlloc;
Fts5PoslistReader *aPoslistReader;
int *aPoslistToIter;
Fts5Iter *apIter[FLEXARRAY];
};
/* Size in bytes of an Fts5TokenDataIter object holding up to N iterators */
#define SZ_FTS5TOKENDATAITER(N) \
(offsetof(Fts5TokenDataIter,apIter) + (N)*sizeof(Fts5Iter))
/*
** The two input arrays - a1[] and a2[] - are in sorted order. This function
** merges the two arrays together and writes the result to output array
** aOut[]. aOut[] is guaranteed to be large enough to hold the result.
**
** Duplicate entries are copied into the output. So the size of the output
|
| ︙ | ︙ | |||
249375 249376 249377 249378 249379 249380 249381 |
pT->nMap++;
}
}
/*
** Sort the contents of the pT->aMap[] array.
**
| | | 250184 250185 250186 250187 250188 250189 250190 250191 250192 250193 250194 250195 250196 250197 250198 |
pT->nMap++;
}
}
/*
** Sort the contents of the pT->aMap[] array.
**
** The sorting algorithm requires a malloc(). If this fails, an error code
** is left in Fts5Index.rc before returning.
*/
static void fts5TokendataIterSortMap(Fts5Index *p, Fts5TokenDataIter *pT){
Fts5TokenDataMap *aTmp = 0;
int nByte = pT->nMap * sizeof(Fts5TokenDataMap);
aTmp = (Fts5TokenDataMap*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
| ︙ | ︙ | |||
249566 249567 249568 249569 249570 249571 249572 |
s.iLastRowid = 0;
s.nBuf = 32;
if( iIdx==0
&& p->pConfig->eDetail==FTS5_DETAIL_FULL
&& p->pConfig->bPrefixInsttoken
){
s.pTokendata = &s2;
| | | 250375 250376 250377 250378 250379 250380 250381 250382 250383 250384 250385 250386 250387 250388 250389 |
s.iLastRowid = 0;
s.nBuf = 32;
if( iIdx==0
&& p->pConfig->eDetail==FTS5_DETAIL_FULL
&& p->pConfig->bPrefixInsttoken
){
s.pTokendata = &s2;
s2.pT = (Fts5TokenDataIter*)fts5IdxMalloc(p, SZ_FTS5TOKENDATAITER(1));
}
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
s.xMerge = fts5MergeRowidLists;
s.xAppend = fts5AppendRowid;
}else{
s.nMerge = FTS5_MERGE_NLIST-1;
|
| ︙ | ︙ | |||
249694 249695 249696 249697 249698 249699 249700 |
/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
*/
static int sqlite3Fts5IndexReinit(Fts5Index *p){
| | > | > | | | 250503 250504 250505 250506 250507 250508 250509 250510 250511 250512 250513 250514 250515 250516 250517 250518 250519 250520 250521 250522 250523 250524 250525 250526 250527 |
/*
** The %_data table is completely empty when this function is called. This
** function populates it with the initial structure objects for each index,
** and the initial version of the "averages" record (a zero-byte blob).
*/
static int sqlite3Fts5IndexReinit(Fts5Index *p){
Fts5Structure *pTmp;
u8 tmpSpace[SZ_FTS5STRUCTURE(1)];
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
pTmp = (Fts5Structure*)tmpSpace;
memset(pTmp, 0, SZ_FTS5STRUCTURE(1));
if( p->pConfig->bContentlessDelete ){
pTmp->nOriginCntr = 1;
}
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, pTmp);
return fts5IndexReturn(p);
}
/*
** Open a new Fts5Index handle. If the bCreate argument is true, create
** and initialize the underlying %_data table.
**
|
| ︙ | ︙ | |||
249910 249911 249912 249913 249914 249915 249916 |
Fts5Iter *pAppend /* Append this iterator */
){
Fts5TokenDataIter *pRet = pIn;
if( p->rc==SQLITE_OK ){
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
| | | 250721 250722 250723 250724 250725 250726 250727 250728 250729 250730 250731 250732 250733 250734 250735 |
Fts5Iter *pAppend /* Append this iterator */
){
Fts5TokenDataIter *pRet = pIn;
if( p->rc==SQLITE_OK ){
if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
int nByte = SZ_FTS5TOKENDATAITER(nAlloc+1);
Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
if( pNew==0 ){
p->rc = SQLITE_NOMEM;
}else{
if( pIn==0 ) memset(pNew, 0, nByte);
pRet = pNew;
|
| ︙ | ︙ | |||
250426 250427 250428 250429 250430 250431 250432 |
Fts5Buffer token = {0, 0, 0};
TokendataSetupCtx ctx;
memset(&ctx, 0, sizeof(ctx));
fts5BufferGrow(&p->rc, &token, nToken+1);
assert( token.p!=0 || p->rc!=SQLITE_OK );
| | > | 251237 251238 251239 251240 251241 251242 251243 251244 251245 251246 251247 251248 251249 251250 251251 251252 |
Fts5Buffer token = {0, 0, 0};
TokendataSetupCtx ctx;
memset(&ctx, 0, sizeof(ctx));
fts5BufferGrow(&p->rc, &token, nToken+1);
assert( token.p!=0 || p->rc!=SQLITE_OK );
ctx.pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
SZ_FTS5TOKENDATAITER(1));
if( p->rc==SQLITE_OK ){
/* Fill in the token prefix to search for */
token.p[0] = FTS5_MAIN_PREFIX;
memcpy(&token.p[1], pToken, nToken);
token.n = nToken+1;
|
| ︙ | ︙ | |||
250557 250558 250559 250560 250561 250562 250563 |
i64 iPos = (((i64)iCol)<<32) + iOff;
assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
assert( pIter->pTokenDataIter || pIter->nSeg>0 );
if( pIter->nSeg>0 ){
/* This is a prefix term iterator. */
if( pT==0 ){
| | > | 251369 251370 251371 251372 251373 251374 251375 251376 251377 251378 251379 251380 251381 251382 251383 251384 |
i64 iPos = (((i64)iCol)<<32) + iOff;
assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
assert( pIter->pTokenDataIter || pIter->nSeg>0 );
if( pIter->nSeg>0 ){
/* This is a prefix term iterator. */
if( pT==0 ){
pT = (Fts5TokenDataIter*)sqlite3Fts5MallocZero(&p->rc,
SZ_FTS5TOKENDATAITER(1));
pIter->pTokenDataIter = pT;
}
if( pT ){
fts5TokendataIterAppendMap(p, pT, pT->terms.n, nToken, iRowid, iPos);
fts5BufferAppendBlob(&p->rc, &pT->terms, nToken, (const u8*)pToken);
}
}else{
|
| ︙ | ︙ | |||
251591 251592 251593 251594 251595 251596 251597 |
*pbTombstone = (int)(iRowid & 0x0001);
}
#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
| | | 252404 252405 252406 252407 252408 252409 252410 252411 252412 252413 252414 252415 252416 252417 252418 |
*pbTombstone = (int)(iRowid & 0x0001);
}
#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid components */
fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
if( iSegid==0 ){
if( iKey==FTS5_AVERAGES_ROWID ){
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{averages} ");
}else{
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{structure}");
|
| ︙ | ︙ | |||
252552 252553 252554 252555 252556 252557 252558 |
** byte of the position list for the corresponding phrase.
*/
struct Fts5Sorter {
sqlite3_stmt *pStmt;
i64 iRowid; /* Current rowid */
const u8 *aPoslist; /* Position lists for current row */
int nIdx; /* Number of entries in aIdx[] */
| | > > | 253365 253366 253367 253368 253369 253370 253371 253372 253373 253374 253375 253376 253377 253378 253379 253380 253381 253382 253383 |
** byte of the position list for the corresponding phrase.
*/
struct Fts5Sorter {
sqlite3_stmt *pStmt;
i64 iRowid; /* Current rowid */
const u8 *aPoslist; /* Position lists for current row */
int nIdx; /* Number of entries in aIdx[] */
int aIdx[FLEXARRAY]; /* Offsets into aPoslist for current row */
};
/* Size (int bytes) of an Fts5Sorter object with N indexes */
#define SZ_FTS5SORTER(N) (offsetof(Fts5Sorter,nIdx)+((N+2)/2)*sizeof(i64))
/*
** Virtual-table cursor object.
**
** iSpecial:
** If this is a 'special' query (refer to function fts5SpecialMatch()),
** then this variable contains the result of the query.
|
| ︙ | ︙ | |||
253432 253433 253434 253435 253436 253437 253438 | int nPhrase; sqlite3_int64 nByte; int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); | | | 254247 254248 254249 254250 254251 254252 254253 254254 254255 254256 254257 254258 254259 254260 254261 | int nPhrase; sqlite3_int64 nByte; int rc; const char *zRank = pCsr->zRank; const char *zRankArgs = pCsr->zRankArgs; nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); nByte = SZ_FTS5SORTER(nPhrase); pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte); if( pSorter==0 ) return SQLITE_NOMEM; memset(pSorter, 0, (size_t)nByte); pSorter->nIdx = nPhrase; /* TODO: It would be better to have some system for reusing statement ** handles here, rather than preparing a new one for each query. But that |
| ︙ | ︙ | |||
255958 255959 255960 255961 255962 255963 255964 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
| | | 256773 256774 256775 256776 256777 256778 256779 256780 256781 256782 256783 256784 256785 256786 256787 |
static void fts5SourceIdFunc(
sqlite3_context *pCtx, /* Function call context */
int nArg, /* Number of args */
sqlite3_value **apUnused /* Function arguments */
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2025-03-16 00:13:29 18bda13e197e4b4ec7464b3e70012f71edc05f73d8b14bb48bad452f81c7e185", -1, SQLITE_TRANSIENT);
}
/*
** Implementation of fts5_locale(LOCALE, TEXT) function.
**
** If parameter LOCALE is NULL, or a zero-length string, then a copy of
** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as
|
| ︙ | ︙ | |||
256183 256184 256185 256186 256187 256188 256189 |
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
** fts5_test_mi.c is compiled and linked into the executable. And call
** its entry point to enable the matchinfo() demo. */
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
if( rc==SQLITE_OK ){
| | | | 256998 256999 257000 257001 257002 257003 257004 257005 257006 257007 257008 257009 257010 257011 257012 257013 |
}
/* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file
** fts5_test_mi.c is compiled and linked into the executable. And call
** its entry point to enable the matchinfo() demo. */
#ifdef SQLITE_FTS5_ENABLE_TEST_MI
if( rc==SQLITE_OK ){
extern int sqlite3Fts5TestRegisterMatchinfoAPI(fts5_api*);
rc = sqlite3Fts5TestRegisterMatchinfoAPI(&pGlobal->api);
}
#endif
return rc;
}
/*
|
| ︙ | ︙ |
Changes to extsrc/sqlite3.h.
| ︙ | ︙ | |||
144 145 146 147 148 149 150 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.50.0" #define SQLITE_VERSION_NUMBER 3050000 | | | 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | ** ** See also: [sqlite3_libversion()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ #define SQLITE_VERSION "3.50.0" #define SQLITE_VERSION_NUMBER 3050000 #define SQLITE_SOURCE_ID "2025-03-16 00:13:29 18bda13e197e4b4ec7464b3e70012f71edc05f73d8b14bb48bad452f81c7e185" /* ** CAPI3REF: Run-Time Library Version Numbers ** KEYWORDS: sqlite3_version sqlite3_sourceid ** ** These interfaces provide the same information as the [SQLITE_VERSION], ** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros |
| ︙ | ︙ | |||
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 | ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database | > > > > > > | 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 | ** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]] ** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS ** to block for up to M milliseconds before failing when attempting to ** obtain a file lock using the xLock or xShmLock methods of the VFS. ** The parameter is a pointer to a 32-bit signed integer that contains ** the value that M is to be set to. Before returning, the 32-bit signed ** integer is overwritten with the previous value of M. ** ** <li>[[SQLITE_FCNTL_BLOCK_ON_CONNECT]] ** The [SQLITE_FCNTL_BLOCK_ON_CONNECT] opcode is used to configure the ** VFS to block when taking a SHARED lock to connect to a wal mode database. ** This is used to implement the functionality associated with ** SQLITE_SETLK_BLOCK_ON_CONNECT. ** ** <li>[[SQLITE_FCNTL_DATA_VERSION]] ** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to ** a database file. The argument is a pointer to a 32-bit unsigned integer. ** The "data version" for the pager is written into the pointer. The ** "data version" changes whenever any change occurs to the corresponding ** database file, either through SQL statements on the same database |
| ︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO | > | 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 | #define SQLITE_FCNTL_CKPT_DONE 37 #define SQLITE_FCNTL_RESERVE_BYTES 38 #define SQLITE_FCNTL_CKPT_START 39 #define SQLITE_FCNTL_EXTERNAL_READER 40 #define SQLITE_FCNTL_CKSM_FILE 41 #define SQLITE_FCNTL_RESET_CACHE 42 #define SQLITE_FCNTL_NULL_IO 43 #define SQLITE_FCNTL_BLOCK_ON_CONNECT 44 /* deprecated names */ #define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE #define SQLITE_SET_LOCKPROXYFILE SQLITE_FCNTL_SET_LOCKPROXYFILE #define SQLITE_LAST_ERRNO SQLITE_FCNTL_LAST_ERRNO |
| ︙ | ︙ | |||
3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 | ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 | ** was defined (using [sqlite3_busy_handler()]) prior to calling ** this routine, that other busy handler is cleared.)^ ** ** See also: [PRAGMA busy_timeout] */ SQLITE_API int sqlite3_busy_timeout(sqlite3*, int ms); /* ** CAPI3REF: Set the Setlk Timeout ** METHOD: sqlite3 ** ** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If ** the VFS supports blocking locks, it sets the timeout in ms used by ** eligible locks taken on wal mode databases by the specified database ** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does ** not support blocking locks, this function is a no-op. ** ** Passing 0 to this function disables blocking locks altogether. Passing ** -1 to this function requests that the VFS blocks for a long time - ** indefinitely if possible. The results of passing any other negative value ** are undefined. ** ** Internally, each SQLite database handle store two timeout values - the ** busy-timeout (used for rollback mode databases, or if the VFS does not ** support blocking locks) and the setlk-timeout (used for blocking locks ** on wal-mode databases). The sqlite3_busy_timeout() method sets both ** values, this function sets only the setlk-timeout value. Therefore, ** to configure separate busy-timeout and setlk-timeout values for a single ** database handle, call sqlite3_busy_timeout() followed by this function. ** ** Whenever the number of connections to a wal mode database falls from ** 1 to 0, the last connection takes an exclusive lock on the database, ** then checkpoints and deletes the wal file. While it is doing this, any ** new connection that tries to read from the database fails with an ** SQLITE_BUSY error. Or, if the SQLITE_SETLK_BLOCK_ON_CONNECT flag is ** passed to this API, the new connection blocks until the exclusive lock ** has been released. */ SQLITE_API int sqlite3_setlk_timeout(sqlite3*, int ms, int flags); /* ** CAPI3REF: Flags for sqlite3_setlk_timeout() */ #define SQLITE_SETLK_BLOCK_ON_CONNECT 0x01 /* ** CAPI3REF: Convenience Routines For Running Queries ** METHOD: sqlite3 ** ** This is a legacy interface that is preserved for backwards compatibility. ** Use of this interface is not recommended. ** |
| ︙ | ︙ | |||
5126 5127 5128 5129 5130 5131 5132 | ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from | | | 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 | ** more threads at the same moment in time. ** ** For all versions of SQLite up to and including 3.6.23.1, a call to ** [sqlite3_reset()] was required after sqlite3_step() returned anything ** other than [SQLITE_ROW] before any subsequent invocation of ** sqlite3_step(). Failure to reset the prepared statement using ** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from ** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1]), ** sqlite3_step() began ** calling [sqlite3_reset()] automatically in this circumstance rather ** than returning [SQLITE_MISUSE]. This is not considered a compatibility ** break because any application that ever receives an SQLITE_MISUSE error ** is broken by definition. The [SQLITE_OMIT_AUTORESET] compile-time option ** can be used to restore the legacy behavior. ** |
| ︙ | ︙ | |||
7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 | ** to be invoked whenever a row is updated, inserted or deleted in ** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. | > > | 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 | ** to be invoked whenever a row is updated, inserted or deleted in ** a [rowid table]. ** ^Any callback set by a previous call to this function ** for the same database connection is overridden. ** ** ^The second argument is a pointer to the function to invoke when a ** row is updated, inserted or deleted in a rowid table. ** ^The update hook is disabled by invoking sqlite3_update_hook() ** with a NULL pointer as the second parameter. ** ^The first argument to the callback is a copy of the third argument ** to sqlite3_update_hook(). ** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE], ** or [SQLITE_UPDATE], depending on the operation that caused the callback ** to be invoked. ** ^The third and fourth arguments to the callback contain pointers to the ** database and table name containing the affected row. |
| ︙ | ︙ |
Changes to skins/default/css.txt.
| ︙ | ︙ | |||
354 355 356 357 358 359 360 |
padding: 0 4px;
}
.content pre, table.numbered-lines > tbody > tr {
hyphens: none;
line-height: 1.25;
}
| | > | 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 |
padding: 0 4px;
}
.content pre, table.numbered-lines > tbody > tr {
hyphens: none;
line-height: 1.25;
}
.content ul:not(.browser) > li {
list-style-type: disc;
}
div.filetree ul li.dir,
div.filetree ul li.subdir,
div.filetree ul li.file{
list-style-type: none;
}
.artifact > .content table,
|
| ︙ | ︙ |
Changes to src/add.c.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 |
/* Cached setting "manifest" */
static int cachedManifest = -1;
static int numManifests;
if( cachedManifest == -1 ){
int i;
Blob repo;
| | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* Cached setting "manifest" */
static int cachedManifest = -1;
static int numManifests;
if( cachedManifest == -1 ){
int i;
Blob repo;
cachedManifest = db_get_manifest_setting(0);
numManifests = 0;
for(i=0; i<count(aManifestflags); i++){
if( cachedManifest&aManifestflags[i].flg ) {
azManifests[numManifests++] = aManifestflags[i].fname;
}
}
blob_zero(&repo);
|
| ︙ | ︙ |
Changes to src/alerts.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 | @ -- a - Announcements @ -- c - Check-ins @ -- f - Forum posts @ -- k - ** Special: Unsubscribed using /oneclickunsub @ -- n - New forum threads @ -- r - Replies to my own forum posts @ -- t - Ticket changes @ -- w - Wiki changes @ -- x - Edits to forum posts @ -- Probably different codes will be added in the future. In the future @ -- we might also add a separate table that allows subscribing to email @ -- notifications for specific branches or tags or tickets. @ -- @ CREATE TABLE repository.subscriber( | > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | @ -- a - Announcements @ -- c - Check-ins @ -- f - Forum posts @ -- k - ** Special: Unsubscribed using /oneclickunsub @ -- n - New forum threads @ -- r - Replies to my own forum posts @ -- t - Ticket changes @ -- u - Elevation of users' permissions (admins only) @ -- w - Wiki changes @ -- x - Edits to forum posts @ -- Probably different codes will be added in the future. In the future @ -- we might also add a separate table that allows subscribing to email @ -- notifications for specific branches or tags or tickets. @ -- @ CREATE TABLE repository.subscriber( |
| ︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 | ** are sent when email-send-method is "relay". There should be an ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ /* | | | 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | ** are sent when email-send-method is "relay". There should be an ** SMTP server configured as a Mail Submission Agent listening on the ** designated host and port and all times. */ /* ** COMMAND: alerts* abbrv-subcom ** ** Usage: %fossil alerts SUBCOMMAND ARGS... ** ** Subcommands: ** ** pending Show all pending alerts. Useful for debugging. ** |
| ︙ | ︙ | |||
1256 1257 1258 1259 1260 1261 1262 |
}
db_set(pSetting->name/*works-like:""*/, g.argv[4], isGlobal);
g.argc = 3;
}
pSetting = setting_info(&nSetting);
for(; nSetting>0; nSetting--, pSetting++ ){
if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
| | | | 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 |
}
db_set(pSetting->name/*works-like:""*/, g.argv[4], isGlobal);
g.argc = 3;
}
pSetting = setting_info(&nSetting);
for(; nSetting>0; nSetting--, pSetting++ ){
if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
print_setting(pSetting, 0, 0);
}
}else
if( strncmp(zCmd, "status", nCmd)==0 ){
Stmt q;
int iCutoff;
int nSetting, n;
static const char *zFmt = "%-29s %d\n";
const Setting *pSetting = setting_info(&nSetting);
db_open_config(1, 0);
verify_all_options();
if( g.argc!=3 ) usage("status");
pSetting = setting_info(&nSetting);
for(; nSetting>0; nSetting--, pSetting++ ){
if( strncmp(pSetting->name,"email-",6)!=0 ) continue;
print_setting(pSetting, 0, 0);
}
n = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentSep");
fossil_print(zFmt/*works-like:"%s%d"*/, "pending-alerts", n);
n = db_int(0,"SELECT count(*) FROM pending_alert WHERE NOT sentDigest");
fossil_print(zFmt/*works-like:"%s%d"*/, "pending-digest-alerts", n);
db_prepare(&q,
"SELECT"
|
| ︙ | ︙ | |||
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 |
if( suname && suname[0]==0 ) suname = 0;
if( PB("sa") ) ssub[nsub++] = 'a';
if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c';
if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
if( g.perm.RdForum && PB("sn") ) ssub[nsub++] = 'n';
if( g.perm.RdForum && PB("sr") ) ssub[nsub++] = 'r';
if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't';
if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w';
if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
ssub[nsub] = 0;
zCode = db_text(0,
"INSERT INTO subscriber(semail,suname,"
" sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip,lastContact)"
"VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q,now()/86400)"
| > | 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 |
if( suname && suname[0]==0 ) suname = 0;
if( PB("sa") ) ssub[nsub++] = 'a';
if( g.perm.Read && PB("sc") ) ssub[nsub++] = 'c';
if( g.perm.RdForum && PB("sf") ) ssub[nsub++] = 'f';
if( g.perm.RdForum && PB("sn") ) ssub[nsub++] = 'n';
if( g.perm.RdForum && PB("sr") ) ssub[nsub++] = 'r';
if( g.perm.RdTkt && PB("st") ) ssub[nsub++] = 't';
if( g.perm.Admin && PB("su") ) ssub[nsub++] = 'u';
if( g.perm.RdWiki && PB("sw") ) ssub[nsub++] = 'w';
if( g.perm.RdForum && PB("sx") ) ssub[nsub++] = 'x';
ssub[nsub] = 0;
zCode = db_text(0,
"INSERT INTO subscriber(semail,suname,"
" sverified,sdonotcall,sdigest,ssub,sctime,mtime,smip,lastContact)"
"VALUES(%Q,%Q,%d,0,%d,%Q,now(),now(),%Q,now()/86400)"
|
| ︙ | ︙ | |||
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 |
** subscription options to "on" */
cgi_set_parameter_nocopy("sa","1",1);
if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sn","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sr","1",1);
if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1);
if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1);
}
@ <p>To receive email notifications for changes to this
@ repository, fill out the form below and press the "Submit" button.</p>
form_begin(0, "%R/subscribe");
@ <table class="subscribe">
@ <tr>
| > | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 |
** subscription options to "on" */
cgi_set_parameter_nocopy("sa","1",1);
if( g.perm.Read ) cgi_set_parameter_nocopy("sc","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sf","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sn","1",1);
if( g.perm.RdForum ) cgi_set_parameter_nocopy("sr","1",1);
if( g.perm.RdTkt ) cgi_set_parameter_nocopy("st","1",1);
if( g.perm.Admin ) cgi_set_parameter_nocopy("su","1",1);
if( g.perm.RdWiki ) cgi_set_parameter_nocopy("sw","1",1);
}
@ <p>To receive email notifications for changes to this
@ repository, fill out the form below and press the "Submit" button.</p>
form_begin(0, "%R/subscribe");
@ <table class="subscribe">
@ <tr>
|
| ︙ | ︙ | |||
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 |
@ <label><input type="checkbox" name="st" %s(PCK("st"))> \
@ Ticket changes</label><br>
}
if( g.perm.RdWiki ){
@ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
@ Wiki</label><br>
}
di = PB("di");
@ </td></tr>
@ <tr>
@ <td class="form_label">Delivery:</td>
@ <td><select size="1" name="di">
@ <option value="0" %s(di?"":"selected")>Individual Emails</option>
@ <option value="1" %s(di?"selected":"")>Daily Digest</option>
| > > > > | 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 |
@ <label><input type="checkbox" name="st" %s(PCK("st"))> \
@ Ticket changes</label><br>
}
if( g.perm.RdWiki ){
@ <label><input type="checkbox" name="sw" %s(PCK("sw"))> \
@ Wiki</label><br>
}
if( g.perm.Admin ){
@ <label><input type="checkbox" name="su" %s(PCK("su"))> \
@ User permission elevation</label>
}
di = PB("di");
@ </td></tr>
@ <tr>
@ <td class="form_label">Delivery:</td>
@ <td><select size="1" name="di">
@ <option value="0" %s(di?"":"selected")>Individual Emails</option>
@ <option value="1" %s(di?"selected":"")>Daily Digest</option>
|
| ︙ | ︙ | |||
1818 1819 1820 1821 1822 1823 1824 |
** in length.) This uniquely identifies the subscriber without
** revealing the complete subscriber code, and hence without
** verifying the email address.
*/
void alert_page(void){
const char *zName = 0; /* Value of the name= query parameter */
Stmt q; /* For querying the database */
| | | 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 |
** in length.) This uniquely identifies the subscriber without
** revealing the complete subscriber code, and hence without
** verifying the email address.
*/
void alert_page(void){
const char *zName = 0; /* Value of the name= query parameter */
Stmt q; /* For querying the database */
int sa, sc, sf, st, su, sw, sx; /* Types of notifications requested */
int sn, sr;
int sdigest = 0, sdonotcall = 0, sverified = 0; /* Other fields */
int isLogin; /* True if logged in as an individual */
const char *ssub = 0; /* Subscription flags */
const char *semail = 0; /* Email address */
const char *smip; /* */
const char *suname = 0; /* Corresponding user.login value */
|
| ︙ | ︙ | |||
1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 |
semail = P("semail");
if( PB("sa") ) newSsub[nsub++] = 'a';
if( g.perm.Read && PB("sc") ) newSsub[nsub++] = 'c';
if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
if( g.perm.RdForum && PB("sn") ) newSsub[nsub++] = 'n';
if( g.perm.RdForum && PB("sr") ) newSsub[nsub++] = 'r';
if( g.perm.RdTkt && PB("st") ) newSsub[nsub++] = 't';
if( g.perm.RdWiki && PB("sw") ) newSsub[nsub++] = 'w';
if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
newSsub[nsub] = 0;
ssub = newSsub;
blob_init(&update, "UPDATE subscriber SET", -1);
blob_append_sql(&update,
" sdonotcall=%d,"
| > | 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 |
semail = P("semail");
if( PB("sa") ) newSsub[nsub++] = 'a';
if( g.perm.Read && PB("sc") ) newSsub[nsub++] = 'c';
if( g.perm.RdForum && PB("sf") ) newSsub[nsub++] = 'f';
if( g.perm.RdForum && PB("sn") ) newSsub[nsub++] = 'n';
if( g.perm.RdForum && PB("sr") ) newSsub[nsub++] = 'r';
if( g.perm.RdTkt && PB("st") ) newSsub[nsub++] = 't';
if( g.perm.Admin && PB("su") ) newSsub[nsub++] = 'u';
if( g.perm.RdWiki && PB("sw") ) newSsub[nsub++] = 'w';
if( g.perm.RdForum && PB("sx") ) newSsub[nsub++] = 'x';
newSsub[nsub] = 0;
ssub = newSsub;
blob_init(&update, "UPDATE subscriber SET", -1);
blob_append_sql(&update,
" sdonotcall=%d,"
|
| ︙ | ︙ | |||
1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 |
}
sa = strchr(ssub,'a')!=0;
sc = strchr(ssub,'c')!=0;
sf = strchr(ssub,'f')!=0;
sn = strchr(ssub,'n')!=0;
sr = strchr(ssub,'r')!=0;
st = strchr(ssub,'t')!=0;
sw = strchr(ssub,'w')!=0;
sx = strchr(ssub,'x')!=0;
smip = db_column_text(&q, 5);
mtime = db_column_text(&q, 7);
sctime = db_column_text(&q, 8);
if( !g.perm.Admin && !sverified ){
if( nName==64 ){
| > | 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 |
}
sa = strchr(ssub,'a')!=0;
sc = strchr(ssub,'c')!=0;
sf = strchr(ssub,'f')!=0;
sn = strchr(ssub,'n')!=0;
sr = strchr(ssub,'r')!=0;
st = strchr(ssub,'t')!=0;
su = strchr(ssub,'u')!=0;
sw = strchr(ssub,'w')!=0;
sx = strchr(ssub,'x')!=0;
smip = db_column_text(&q, 5);
mtime = db_column_text(&q, 7);
sctime = db_column_text(&q, 8);
if( !g.perm.Admin && !sverified ){
if( nName==64 ){
|
| ︙ | ︙ | |||
2095 2096 2097 2098 2099 2100 2101 |
}
if( g.perm.RdTkt ){
@ <label><input type="checkbox" name="st" %s(st?"checked":"")>\
@ Ticket changes</label><br>
}
if( g.perm.RdWiki ){
@ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
| | > > > > > > > > | 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 |
}
if( g.perm.RdTkt ){
@ <label><input type="checkbox" name="st" %s(st?"checked":"")>\
@ Ticket changes</label><br>
}
if( g.perm.RdWiki ){
@ <label><input type="checkbox" name="sw" %s(sw?"checked":"")>\
@ Wiki</label><br>
}
if( g.perm.Admin ){
/* Corner-case bug: if an admin assigns 'u' to a non-admin, that
** subscription will get removed if the user later edits their
** subscriptions, as non-admins are not permitted to add that
** subscription. */
@ <label><input type="checkbox" name="su" %s(su?"checked":"")>\
@ User permission elevation</label>
}
@ </td></tr>
if( strchr(ssub,'k')!=0 ){
@ <tr><td></td><td> ↑
@ Note: User did a one-click unsubscribe</td></tr>
}
@ <tr>
|
| ︙ | ︙ | |||
2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 |
**
** c A new check-in
** f An original forum post
** n New forum threads
** r Replies to my forum posts
** x An edit to a prior forum post
** t A new ticket or a change to an existing ticket
** w A change to a wiki page
** x Edits to forum posts
*/
struct EmailEvent {
| > | | 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 |
**
** c A new check-in
** f An original forum post
** n New forum threads
** r Replies to my forum posts
** x An edit to a prior forum post
** t A new ticket or a change to an existing ticket
** u A user was added or received new permissions
** w A change to a wiki page
** x Edits to forum posts
*/
struct EmailEvent {
int type; /* 'c', 'f', 'n', 'r', 't', 'u', 'w', 'x' */
int needMod; /* Pending moderator approval */
Blob hdr; /* Header content, for forum entries */
Blob txt; /* Text description to appear in an alert */
char *zFromName; /* Human name of the sender */
char *zPriors; /* Upthread sender IDs for forum posts */
EmailEvent *pNext; /* Next in chronological order */
};
|
| ︙ | ︙ | |||
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 |
"on the %s Fossil repository at %s:\n\n",
zRepoName, zUrl
);
if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
blob_appendf(pBody, "\n"
"If you take no action, your subscription will expire and you will be\n"
"unsubscribed in about %d days. To make other changes or to unsubscribe\n"
"immediately, visit the following webpage:\n\n"
" %s/alerts/%s\n\n",
ALERT_RENEWAL_MSG_FREQUENCY, zUrl, zCode
| > | 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 |
"on the %s Fossil repository at %s:\n\n",
zRepoName, zUrl
);
if( strchr(zSub, 'a') ) blob_appendf(pBody, " * Announcements\n");
if( strchr(zSub, 'c') ) blob_appendf(pBody, " * Check-ins\n");
if( strchr(zSub, 'f') ) blob_appendf(pBody, " * Forum posts\n");
if( strchr(zSub, 't') ) blob_appendf(pBody, " * Ticket changes\n");
if( strchr(zSub, 'u') ) blob_appendf(pBody, " * User permission elevation\n");
if( strchr(zSub, 'w') ) blob_appendf(pBody, " * Wiki changes\n");
blob_appendf(pBody, "\n"
"If you take no action, your subscription will expire and you will be\n"
"unsubscribed in about %d days. To make other changes or to unsubscribe\n"
"immediately, visit the following webpage:\n\n"
" %s/alerts/%s\n\n",
ALERT_RENEWAL_MSG_FREQUENCY, zUrl, zCode
|
| ︙ | ︙ | |||
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 |
char xType = '*';
if( strpbrk(zCap,"as")==0 ){
switch( p->type ){
case 'x': case 'f':
case 'n': case 'r': xType = '5'; break;
case 't': xType = 'q'; break;
case 'w': xType = 'l'; break;
}
if( strchr(zCap,xType)==0 ) continue;
}
}else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
/* Setup and admin users can get any notification that does not
** require moderation */
}else{
/* Other users only see the alert if they have sufficient
** privilege to view the event itself */
char xType = '*';
switch( p->type ){
case 'c': xType = 'o'; break;
case 'x': case 'f':
case 'n': case 'r': xType = '2'; break;
case 't': xType = 'r'; break;
case 'w': xType = 'j'; break;
}
if( strchr(zCap,xType)==0 ) continue;
}
if( blob_size(&p->hdr)>0 ){
/* This alert should be sent as a separate email */
Blob fhdr, fbody;
blob_init(&fhdr, 0, 0);
| > > | 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 |
char xType = '*';
if( strpbrk(zCap,"as")==0 ){
switch( p->type ){
case 'x': case 'f':
case 'n': case 'r': xType = '5'; break;
case 't': xType = 'q'; break;
case 'w': xType = 'l'; break;
/* Note: case 'u' is not handled here */
}
if( strchr(zCap,xType)==0 ) continue;
}
}else if( strchr(zCap,'s')!=0 || strchr(zCap,'a')!=0 ){
/* Setup and admin users can get any notification that does not
** require moderation */
}else{
/* Other users only see the alert if they have sufficient
** privilege to view the event itself */
char xType = '*';
switch( p->type ){
case 'c': xType = 'o'; break;
case 'x': case 'f':
case 'n': case 'r': xType = '2'; break;
case 't': xType = 'r'; break;
case 'w': xType = 'j'; break;
/* Note: case 'u' is not handled here */
}
if( strchr(zCap,xType)==0 ) continue;
}
if( blob_size(&p->hdr)>0 ){
/* This alert should be sent as a separate email */
Blob fhdr, fbody;
blob_init(&fhdr, 0, 0);
|
| ︙ | ︙ |
Changes to src/allrepo.c.
| ︙ | ︙ | |||
49 50 51 52 53 54 55 |
int i;
for(i=iStart; i<g.argc; i++){
blob_appendf(pExtra, " %s", g.argv[i]);
}
}
/*
| | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
int i;
for(i=iStart; i<g.argc; i++){
blob_appendf(pExtra, " %s", g.argv[i]);
}
}
/*
** COMMAND: all abbrv-subcom
**
** Usage: %fossil all SUBCOMMAND ...
**
** The ~/.fossil file records the location of all repositories for a
** user. This command performs certain operations on all repositories
** that can be useful before or after a period of disconnected operation.
**
|
| ︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
}
}else if( fossil_strcmp(zCmd, "repack")==0 ){
zCmd = "repack";
}else if( fossil_strcmp(zCmd, "set")==0
|| fossil_strcmp(zCmd, "setting")==0
|| fossil_strcmp(zCmd, "settings")==0 ){
zCmd = "settings -R";
collect_argv(&extra, 3);
}else if( fossil_strcmp(zCmd, "unset")==0 ){
zCmd = "unset -R";
collect_argv(&extra, 3);
}else if( fossil_strcmp(zCmd, "fts-config")==0 ){
zCmd = "fts-config -R";
collect_argv(&extra, 3);
| > | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
}
}else if( fossil_strcmp(zCmd, "repack")==0 ){
zCmd = "repack";
}else if( fossil_strcmp(zCmd, "set")==0
|| fossil_strcmp(zCmd, "setting")==0
|| fossil_strcmp(zCmd, "settings")==0 ){
zCmd = "settings -R";
collect_argument(&extra, "changed", 0);
collect_argv(&extra, 3);
}else if( fossil_strcmp(zCmd, "unset")==0 ){
zCmd = "unset -R";
collect_argv(&extra, 3);
}else if( fossil_strcmp(zCmd, "fts-config")==0 ){
zCmd = "fts-config -R";
collect_argv(&extra, 3);
|
| ︙ | ︙ |
Changes to src/backlink.c.
| ︙ | ︙ | |||
429 430 431 432 433 434 435 | ); backlink_extract(blob_str(&in),mimetype,srcid,srctype,mtime,0); blob_reset(&in); } /* | | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
);
backlink_extract(blob_str(&in),mimetype,srcid,srctype,mtime,0);
blob_reset(&in);
}
/*
** COMMAND: test-relink-wiki
**
** Usage: %fossil test-relink-wiki WIKI-PAGE-NAME
**
** Run the backlink_wiki_refresh() procedure on the wiki page
** named. WIKI-PAGE-NAME can be a glob pattern or a prefix
** of the wiki page.
*/
void test_wiki_relink_cmd(void){
Stmt q;
|
| ︙ | ︙ |
Changes to src/bisect.c.
| ︙ | ︙ | |||
35 36 37 38 39 40 41 |
** Find the shortest path between bad and good.
*/
void bisect_path(void){
PathNode *p;
bisect.bad = db_lget_int("bisect-bad", 0);
bisect.good = db_lget_int("bisect-good", 0);
if( bisect.good>0 && bisect.bad==0 ){
| | | | | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
** Find the shortest path between bad and good.
*/
void bisect_path(void){
PathNode *p;
bisect.bad = db_lget_int("bisect-bad", 0);
bisect.good = db_lget_int("bisect-good", 0);
if( bisect.good>0 && bisect.bad==0 ){
path_shortest(bisect.good, bisect.good, 0, 0, 0, 0);
}else if( bisect.bad>0 && bisect.good==0 ){
path_shortest(bisect.bad, bisect.bad, 0, 0, 0, 0);
}else if( bisect.bad==0 && bisect.good==0 ){
fossil_fatal("neither \"good\" nor \"bad\" versions have been identified");
}else{
Bag skip;
int bDirect = bisect_option("direct-only");
char *zLog = db_lget("bisect-log","");
Blob log, id;
bag_init(&skip);
blob_init(&log, zLog, -1);
while( blob_token(&log, &id) ){
if( blob_str(&id)[0]=='s' ){
bag_insert(&skip, atoi(blob_str(&id)+1));
}
}
blob_reset(&log);
p = path_shortest(bisect.good, bisect.bad, bDirect, 0, &skip, 0);
bag_clear(&skip);
if( p==0 ){
char *zBad = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.bad);
char *zGood = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.good);
fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
zGood, zBad);
}
|
| ︙ | ︙ | |||
290 291 292 293 294 295 296 |
}
}
if( iCurrent>0 ){
bisect_log_append(&ins, ++cnt, "CURRENT", iCurrent);
}
if( bDetail && lastGood>0 && lastBad>0 ){
PathNode *p;
| | | 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
}
}
if( iCurrent>0 ){
bisect_log_append(&ins, ++cnt, "CURRENT", iCurrent);
}
if( bDetail && lastGood>0 && lastBad>0 ){
PathNode *p;
p = path_shortest(lastGood, lastBad, bisect_option("direct-only"),0, 0, 0);
while( p ){
bisect_log_append(&ins, ++cnt, 0, p->rid);
p = p->u.pTo;
}
path_reset();
}
db_exec_sql(blob_sql_text(&ins));
|
| ︙ | ︙ |
Changes to src/blob.c.
| ︙ | ︙ | |||
1992 1993 1994 1995 1996 1997 1998 |
/* Make sure the blob contains two terminating 0-bytes */
blob_append(pBlob, "\000\000", 3);
zUtf8 = blob_str(pBlob) + bomSize;
zUtf8 = fossil_unicode_to_utf8(zUtf8);
blob_reset(pBlob);
blob_set_dynamic(pBlob, zUtf8);
}else if( useMbcs && invalid_utf8(pBlob) ){
| | | 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 |
/* Make sure the blob contains two terminating 0-bytes */
blob_append(pBlob, "\000\000", 3);
zUtf8 = blob_str(pBlob) + bomSize;
zUtf8 = fossil_unicode_to_utf8(zUtf8);
blob_reset(pBlob);
blob_set_dynamic(pBlob, zUtf8);
}else if( useMbcs && invalid_utf8(pBlob) ){
#if defined(_WIN32)
zUtf8 = fossil_mbcs_to_utf8(blob_str(pBlob));
blob_reset(pBlob);
blob_append(pBlob, zUtf8, -1);
fossil_mbcs_free(zUtf8);
#else
blob_cp1252_to_utf8(pBlob);
#endif /* _WIN32 */
|
| ︙ | ︙ |
Changes to src/branch.c.
| ︙ | ︙ | |||
596 597 598 599 600 601 602 | ** COMMAND: branch ** ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? ** ** Run various subcommands to manage branches of the open repository or ** of the repository identified by the -R or --repository option. ** | | | | | | | | 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 | ** COMMAND: branch ** ** Usage: %fossil branch SUBCOMMAND ... ?OPTIONS? ** ** Run various subcommands to manage branches of the open repository or ** of the repository identified by the -R or --repository option. ** ** > fossil branch close|reopen ?OPTIONS? BRANCH-NAME ?...BRANCH-NAMES? ** ** Adds or cancels the "closed" tag to one or more branches. ** It accepts arbitrary unambiguous symbolic names but ** will only resolve check-in names and skips any which resolve ** to non-leaf check-ins. ** ** Options: ** -n|--dry-run Do not commit changes, but dump artifact ** to stdout ** -v|--verbose Output more information ** --date-override DATE DATE to use instead of 'now' ** --user-override USER USER to use instead of the current default ** ** > fossil branch current ** ** Print the name of the branch for the current check-out ** ** > fossil branch hide|unhide ?OPTIONS? BRANCH-NAME ?...BRANCH-NAMES? ** ** Adds or cancels the "hidden" tag for the specified branches or ** or check-in IDs. Accepts the same options as the close ** subcommand. ** ** > fossil branch info BRANCH-NAME ** ** Print information about a branch ** ** > fossil branch list|ls ?OPTIONS? ?GLOB? ** > fossil branch lsh ?OPTIONS? ?LIMIT? ** ** List all branches. ** ** Options: ** -a|--all List all branches. Default show only open branches ** -c|--closed List closed branches ** -m|--merged List branches merged into the current branch |
| ︙ | ︙ | |||
651 652 653 654 655 656 657 | ** If GLOB is given, show only branches matching the pattern. ** ** The "lsh" variant of this subcommand shows recently changed branches, ** and accepts an optional LIMIT argument (defaults to 5) to cap output, ** but no GLOB argument. All other options are supported, with -t being ** an implied no-op. ** | | | 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 | ** If GLOB is given, show only branches matching the pattern. ** ** The "lsh" variant of this subcommand shows recently changed branches, ** and accepts an optional LIMIT argument (defaults to 5) to cap output, ** but no GLOB argument. All other options are supported, with -t being ** an implied no-op. ** ** > fossil branch new BRANCH-NAME BASIS ?OPTIONS? ** ** Create a new branch BRANCH-NAME off of check-in BASIS. ** ** Options: ** --private Branch is private (i.e., remains local) ** --bgcolor COLOR Use COLOR instead of automatic background ** --nosign Do not sign the manifest for the check-in |
| ︙ | ︙ | |||
868 869 870 871 872 873 874 |
const char *zMergeTo = db_column_text(&q, 3);
int nCkin = db_column_int(&q, 4);
const char *zLastCkin = db_column_text(&q, 5);
const char *zBgClr = db_column_text(&q, 6);
char *zAge = human_readable_age(rNow - rMtime);
sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
| > | | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 |
const char *zMergeTo = db_column_text(&q, 3);
int nCkin = db_column_int(&q, 4);
const char *zLastCkin = db_column_text(&q, 5);
const char *zBgClr = db_column_text(&q, 6);
char *zAge = human_readable_age(rNow - rMtime);
sqlite3_int64 iMtime = (sqlite3_int64)(rMtime*86400.0);
if( zMergeTo && zMergeTo[0]==0 ) zMergeTo = 0;
if( zBgClr ) zBgClr = reasonable_bg_color(zBgClr, 0);
if( zBgClr==0 ){
if( zBranch==0 || strcmp(zBranch,"trunk")==0 ){
zBgClr = 0;
}else{
zBgClr = hash_color(zBranch);
}
}
if( zBgClr && zBgClr[0] && show_colors ){
|
| ︙ | ︙ |
Changes to src/builtin.c.
| ︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
}
}
return -1;
}
/*
** Return a pointer to built-in content
*/
const unsigned char *builtin_file(const char *zFilename, int *piSize){
int i = builtin_file_index(zFilename);
if( i>=0 ){
if( piSize ) *piSize = aBuiltinFiles[i].nByte;
return aBuiltinFiles[i].pData;
}else{
if( piSize ) *piSize = 0;
return 0;
}
}
const char *builtin_text(const char *zFilename){
return (char*)builtin_file(zFilename, 0);
}
| > > > > > > > > > > > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
}
}
return -1;
}
/*
** Return a pointer to built-in content
**
** If the filename contains "-vNNNNNNNN" just before the final file
** suffix, where each N is a random digit, then omit that part of the
** filename before doing the lookup. The extra -vNNNNNNNN was added
** to defeat overly aggressive caching by web browsers. There must be
** at least 8 digits in NNNNNNNN but more than 8 are allowed.
*/
const unsigned char *builtin_file(const char *zFilename, int *piSize){
int i = builtin_file_index(zFilename);
if( i>=0 ){
if( piSize ) *piSize = aBuiltinFiles[i].nByte;
return aBuiltinFiles[i].pData;
}else{
char *zV = strstr(zFilename, "-v");
if( zV!=0 ){
for(i=0; fossil_isdigit(zV[i+2]); i++){}
if( i>=8 && zV[i+2]=='.' ){
char *zNew = mprintf("%.*s%s", (int)(zV-zFilename), zFilename, zV+i+2);
const unsigned char *pRes = builtin_file(zNew, piSize);
fossil_free(zNew);
return pRes;
}
}
if( piSize ) *piSize = 0;
return 0;
}
}
const char *builtin_text(const char *zFilename){
return (char*)builtin_file(zFilename, 0);
}
|
| ︙ | ︙ |
Changes to src/cache.c.
| ︙ | ︙ | |||
253 254 255 256 257 258 259 |
** database already exists.
*/
void cache_initialize(void){
sqlite3_close(cacheOpen(1));
}
/*
| | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
** database already exists.
*/
void cache_initialize(void){
sqlite3_close(cacheOpen(1));
}
/*
** COMMAND: cache* abbrv-subcom
**
** Usage: %fossil cache SUBCOMMAND
**
** Manage the cache used for potentially expensive web pages such as
** /zip and /tarball. SUBCOMMAND can be:
**
** clear Remove all entries from the cache.
|
| ︙ | ︙ |
Changes to src/cgi.c.
| ︙ | ︙ | |||
686 687 688 689 690 691 692 693 | } return zRef; } /* ** Return true if the current request is coming from the same origin. */ | > > > > | > > > > > > > | > | > > > > > > > > | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 |
}
return zRef;
}
/*
** Return true if the current request is coming from the same origin.
**
** If the request comes from a different origin and bErrorLog is true, then
** put a warning message on the error log as this was a possible hack
** attempt.
*/
int cgi_same_origin(int bErrorLog){
const char *zRef;
char *zToFree = 0;
int nBase;
int rc;
if( g.zBaseURL==0 ) return 0;
zRef = P("HTTP_REFERER");
if( zRef==0 ) return 0;
if( strchr(zRef,'%')!=0 ){
zToFree = strdup(zRef);
dehttpize(zToFree);
zRef = zToFree;
}
nBase = (int)strlen(g.zBaseURL);
if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ){
rc = 0;
}else if( zRef[nBase]!=0 && zRef[nBase]!='/' ){
rc = 0;
}else{
rc = 1;
}
if( rc==0 && bErrorLog && fossil_strcmp(P("REQUST_METHOD"),"POST")==0 ){
fossil_errorlog("warning: POST from different origin");
}
fossil_free(zToFree);
return rc;
}
/*
** Return true if the current CGI request is a POST request
*/
static int cgi_is_post_request(void){
const char *zMethod = P("REQUEST_METHOD");
|
| ︙ | ︙ | |||
731 732 733 734 735 736 737 |
** 1: Request comes from the same origin
** 2: (1) plus it is a POST request
** 3: (2) plus there is a valid "csrf" token in the request
*/
int cgi_csrf_safe(int securityLevel){
if( g.okCsrf<0 ) return 0;
if( g.okCsrf==0 ){
| | | 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
** 1: Request comes from the same origin
** 2: (1) plus it is a POST request
** 3: (2) plus there is a valid "csrf" token in the request
*/
int cgi_csrf_safe(int securityLevel){
if( g.okCsrf<0 ) return 0;
if( g.okCsrf==0 ){
if( !cgi_same_origin(1) ){
g.okCsrf = -1;
}else{
g.okCsrf = 1;
if( cgi_is_post_request() ){
g.okCsrf = 2;
if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
g.okCsrf = 3;
|
| ︙ | ︙ |
Changes to src/checkin.c.
| ︙ | ︙ | |||
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 |
Blob *pComment,
char *zInit,
CheckinInfo *p,
int parent_rid,
int dryRunFlag
){
Blob prompt;
#if defined(_WIN32) || defined(__CYGWIN__)
int bomSize;
const unsigned char *bom = get_utf8_bom(&bomSize);
blob_init(&prompt, (const char *) bom, bomSize);
if( zInit && zInit[0]){
blob_append(&prompt, zInit, -1);
}
#else
blob_init(&prompt, zInit, -1);
#endif
blob_append(&prompt,
"\n"
| > | | | > > > > > > > > > > > > > > > > > > > > > > > | 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
Blob *pComment,
char *zInit,
CheckinInfo *p,
int parent_rid,
int dryRunFlag
){
Blob prompt;
int wikiFlags;
#if defined(_WIN32) || defined(__CYGWIN__)
int bomSize;
const unsigned char *bom = get_utf8_bom(&bomSize);
blob_init(&prompt, (const char *) bom, bomSize);
if( zInit && zInit[0]){
blob_append(&prompt, zInit, -1);
}
#else
blob_init(&prompt, zInit, -1);
#endif
blob_append(&prompt,
"\n"
"# Enter the commit message. Formatting rules:\n"
"# * Lines beginning with # are ignored.\n",
-1
);
wikiFlags = wiki_convert_flags(1);
if( wikiFlags & WIKI_LINKSONLY ){
blob_append(&prompt,"# * Hyperlinks inside of [...]\n", -1);
if( wikiFlags & WIKI_NEWLINE ){
blob_append(&prompt,
"# * Newlines are significant and are displayed as written\n", -1);
}else{
blob_append(&prompt,
"# * Newlines are interpreted as ordinary spaces\n",
-1
);
}
blob_append(&prompt,
"# * All other text will be displayed as written\n", -1);
}else{
blob_append(&prompt,
"# * Hyperlinks: [target] or [target|display-text]\n"
"# * Blank lines cause a paragraph break\n"
"# * Other text rendered as if it where HTML\n", -1
);
}
blob_append(&prompt, "#\n", 2);
if( dryRunFlag ){
blob_appendf(&prompt, "# DRY-RUN: This is a test commit. No changes "
"will be made to the repository\n#\n");
}
blob_appendf(&prompt, "# user: %s\n",
p->zUserOvrd ? p->zUserOvrd : login_name());
if( p->zBranch && p->zBranch[0] ){
|
| ︙ | ︙ | |||
2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 |
*/
static int tagCmp(const void *a, const void *b){
char **pA = (char**)a;
char **pB = (char**)b;
return fossil_strcmp(pA[0], pB[0]);
}
/*
** COMMAND: ci#
** COMMAND: commit
**
** Usage: %fossil commit ?OPTIONS? ?FILE...?
** or: %fossil ci ?OPTIONS? ?FILE...?
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | < | | < < > | | | < < < < < < < < < < < < < < < < | < > | > > | | | < | > > | > > | | < < | < < < | 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 |
*/
static int tagCmp(const void *a, const void *b){
char **pA = (char**)a;
char **pB = (char**)b;
return fossil_strcmp(pA[0], pB[0]);
}
/*
** SETTING: verify-comments width=8 default=on
**
** This setting determines how much sanity checking, if any, the
** "fossil commit" and "fossil amend" commands do against check-in
** comments. Recognized values:
**
** on (Default) Check for bad syntax and/or broken hyperlinks
** in check-in comments and offer the user a chance to
** continue editing for interactive sessions, or simply
** abort the commit if the comment was entered using -m or -M
**
** off Do not do syntax checking of any kind
**
** preview Do all the same checks as "on" but also always preview the
** check-in comment to the user during interactive sessions
** even if no obvious errors are found, and provide an
** opportunity to accept or re-edit
*/
#if INTERFACE
#define COMCK_MARKUP 0x01 /* Check for mistakes */
#define COMCK_PREVIEW 0x02 /* Always preview, even if no issues found */
#endif /* INTERFACE */
/*
** Check for possible formatting errors in the comment string pComment.
**
** If issues are found, write an appropriate error notice, probably also
** including the complete text of the comment formatted to highlight the
** problem, to stdout and return non-zero. The return value is some
** combination of the COMCK_* flags, depending on what went wrong.
**
** If no issues are seen, do not output anything and return zero.
*/
int verify_comment(Blob *pComment, int mFlags){
Blob in, html;
int mResult;
int rc = mFlags & COMCK_PREVIEW;
int wFlags;
if( mFlags==0 ) return 0;
blob_init(&in, blob_str(pComment), -1);
blob_init(&html, 0, 0);
wFlags = wiki_convert_flags(0);
wFlags &= ~WIKI_NOBADLINKS;
wFlags |= WIKI_MARK;
mResult = wiki_convert(&in, &html, wFlags);
if( mResult & RENDER_ANYERROR ) rc |= COMCK_MARKUP;
if( rc ){
int htot = ((wFlags & WIKI_NEWLINE)!=0 ? 0 : HTOT_FLOW)|HTOT_TRIM;
Blob txt;
if( terminal_is_vt100() ) htot |= HTOT_VT100;
blob_init(&txt, 0, 0);
html_to_plaintext(blob_str(&html), &txt, htot);
if( rc & COMCK_MARKUP ){
fossil_print("Possible format errors in the check-in comment:\n\n ");
}else{
fossil_print("Preview of the check-in comment:\n\n ");
}
if( wFlags & WIKI_NEWLINE ){
Blob line;
char *zIndent = "";
while( blob_line(&txt, &line) ){
fossil_print("%s%b", zIndent, &line);
zIndent = " ";
}
fossil_print("\n");
}else{
comment_print(blob_str(&txt), 0, 3, -1, get_comment_format());
}
fossil_print("\n");
fflush(stdout);
blob_reset(&txt);
}
blob_reset(&html);
blob_reset(&in);
return rc;
}
/*
** COMMAND: ci#
** COMMAND: commit
**
** Usage: %fossil commit ?OPTIONS? ?FILE...?
** or: %fossil ci ?OPTIONS? ?FILE...?
**
** Create a new check-in containing all of the changes in the current
** check-out. All changes are committed unless some subset of files
** is specified on the command line, in which case only the named files
** become part of the new check-in.
**
** You will be prompted to enter a check-in comment unless the comment
** has been specified on the command-line using "-m" or "-M". The
** text editor used is determined by the "editor" setting, or by the
** "VISUAL" or "EDITOR" environment variables. Commit message text is
** interpreted as fossil-wiki format. Potentially misformatted check-in
** comment text is detected and reported unless the --no-verify-comment
** option is used.
**
** The --branch option followed by a branch name causes the new
** check-in to be placed in a newly-created branch with name specified.
**
** A check-in is not permitted to fork unless the --allow-fork option
** appears. An empty check-in (i.e. with nothing changed) is not
** allowed unless the --allow-empty option appears. A check-in may not
** be older than its ancestor unless the --allow-older option appears.
** If any files in the check-in appear to contain unresolved merge
** conflicts, the check-in will not be allowed unless the
** --allow-conflict option is present. In addition, the entire
** check-in process may be aborted if a file contains content that
** appears to be binary, Unicode text, or text with CR/LF line endings
** unless the interactive user chooses to proceed. If there is no
** interactive user or these warnings should be skipped for some other
** reason, the --no-warnings option may be used. A check-in is not
** allowed against a closed leaf.
**
** The --private option creates a private check-in that is never synced.
** Children of private check-ins are automatically private.
**
** The --tag option applies the symbolic tag name to the check-in.
** The --tag option can be repeated to assign multiple tags to a check-in.
** For example: "... --tag release --tag version-1.2.3 ..."
**
** Options:
** --allow-conflict Allow unresolved merge conflicts
** --allow-empty Allow a commit with no changes
** --allow-fork Allow the commit to fork
** --allow-older Allow a commit older than its ancestor
** --baseline Use a baseline manifest in the commit process
** --bgcolor COLOR Apply COLOR to this one check-in only
** --branch NEW-BRANCH-NAME Check in to this new branch
** --branchcolor COLOR Apply given COLOR to the branch
** --close Close the branch being committed
** --date-override DATETIME Make DATETIME the time of the check-in.
** Useful when importing historical check-ins
** from another version control system.
** --delta Use a delta manifest in the commit process
** --hash Verify file status using hashing rather
** than relying on filesystem mtimes
** --if-changes Make this command a silent no-op if there
** are no changes
** --ignore-clock-skew If a clock skew is detected, ignore it and
** behave as if the user had entered 'yes' to
** the question of whether to proceed despite
** the skew.
** --ignore-oversize Do not warn the user about oversized files
** --integrate Close all merged-in branches
** -m|--comment COMMENT-TEXT Use COMMENT-TEXT as the check-in comment
** -M|--message-file FILE Read the check-in comment from FILE
** -n|--dry-run Do not actually create a new check-in. Just
** show what would have happened. For debugging.
** -v|--verbose Show a diff in the commit message prompt
** --no-prompt This option disables prompting the user for
** input and assumes an answer of 'No' for every
** question.
** --no-warnings Omit all warnings about file contents
** --no-verify Do not run before-commit hooks
** --no-verify-comment Do not validate the check-in comment
** --nosign Do not attempt to sign this commit with gpg
** --nosync Do not auto-sync prior to committing
** --override-lock Allow a check-in even though parent is locked
** --private Never sync the resulting check-in and make
** all descendants private too.
** --proxy PROXY Use PROXY as http proxy during sync operation
** --tag TAG-NAME Add TAG-NAME to the check-in. May be repeated.
** --trace Debug tracing
** --user-override USER Record USER as the login that created the
** new check-in, rather that the current user.
**
** See also: [[branch]], [[changes]], [[update]], [[extras]], [[sync]]
*/
void commit_cmd(void){
int hasChanges; /* True if unsaved changes exist */
int vid; /* blob-id of parent version */
int nrid; /* blob-id of a modified file */
|
| ︙ | ︙ | |||
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 | int forceDelta = 0; /* Force a delta-manifest */ int forceBaseline = 0; /* Force a baseline-manifest */ int allowConflict = 0; /* Allow unresolve merge conflicts */ int allowEmpty = 0; /* Allow a commit with no changes */ int onlyIfChanges = 0; /* No-op if there are no changes */ int allowFork = 0; /* Allow the commit to fork */ int allowOlder = 0; /* Allow a commit older than its ancestor */ char *zManifestFile; /* Name of the manifest file */ int useCksum; /* True if checksums should be computed and verified */ int outputManifest; /* True to output "manifest" and "manifest.uuid" */ int dryRunFlag; /* True for a test run. Debugging only */ CheckinInfo sCiInfo; /* Information about this check-in */ const char *zComFile; /* Read commit message from this file */ int nTag = 0; /* Number of --tag arguments */ | > | 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 | int forceDelta = 0; /* Force a delta-manifest */ int forceBaseline = 0; /* Force a baseline-manifest */ int allowConflict = 0; /* Allow unresolve merge conflicts */ int allowEmpty = 0; /* Allow a commit with no changes */ int onlyIfChanges = 0; /* No-op if there are no changes */ int allowFork = 0; /* Allow the commit to fork */ int allowOlder = 0; /* Allow a commit older than its ancestor */ int noVerifyCom = 0; /* Allow suspicious check-in comments */ char *zManifestFile; /* Name of the manifest file */ int useCksum; /* True if checksums should be computed and verified */ int outputManifest; /* True to output "manifest" and "manifest.uuid" */ int dryRunFlag; /* True for a test run. Debugging only */ CheckinInfo sCiInfo; /* Information about this check-in */ const char *zComFile; /* Read commit message from this file */ int nTag = 0; /* Number of --tag arguments */ |
| ︙ | ︙ | |||
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 |
Blob ans; /* Answer to continuation prompts */
char cReply; /* First character of ans */
int bRecheck = 0; /* Repeat fork and closed-branch checks*/
int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
int mxSize;
char *zCurBranch = 0; /* The current branch name of checkout */
char *zNewBranch = 0; /* The branch name after update */
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
/* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
noSign = find_option("nosign",0,0)!=0;
if( find_option("nosync",0,0) ) g.fNoSync = 1;
| > | 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 |
Blob ans; /* Answer to continuation prompts */
char cReply; /* First character of ans */
int bRecheck = 0; /* Repeat fork and closed-branch checks*/
int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
int mxSize;
char *zCurBranch = 0; /* The current branch name of checkout */
char *zNewBranch = 0; /* The branch name after update */
int ckComFlgs; /* Flags passed to verify_comment() */
memset(&sCiInfo, 0, sizeof(sCiInfo));
url_proxy_options();
/* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
noSign = find_option("nosign",0,0)!=0;
if( find_option("nosync",0,0) ) g.fNoSync = 1;
|
| ︙ | ︙ | |||
2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 |
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
zComment = find_option("comment","m",1);
forceFlag = find_option("force", "f", 0)!=0;
allowConflict = find_option("allow-conflict",0,0)!=0;
allowEmpty = find_option("allow-empty",0,0)!=0;
onlyIfChanges = find_option("if-changes",0,0)!=0;
allowFork = find_option("allow-fork",0,0)!=0;
if( find_option("override-lock",0,0)!=0 ) allowFork = 1;
allowOlder = find_option("allow-older",0,0)!=0;
noPrompt = find_option("no-prompt", 0, 0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
noVerify = find_option("no-verify",0,0)!=0;
bTrace = find_option("trace",0,0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
| > > > > > | | > > < | > > > > > > | 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 |
if( !dryRunFlag ){
dryRunFlag = find_option("test",0,0)!=0; /* deprecated */
}
zComment = find_option("comment","m",1);
forceFlag = find_option("force", "f", 0)!=0;
allowConflict = find_option("allow-conflict",0,0)!=0;
allowEmpty = find_option("allow-empty",0,0)!=0;
noVerifyCom = find_option("no-verify-comment",0,0)!=0;
onlyIfChanges = find_option("if-changes",0,0)!=0;
allowFork = find_option("allow-fork",0,0)!=0;
if( find_option("override-lock",0,0)!=0 ) allowFork = 1;
allowOlder = find_option("allow-older",0,0)!=0;
noPrompt = find_option("no-prompt", 0, 0)!=0;
noWarningFlag = find_option("no-warnings", 0, 0)!=0;
noVerify = find_option("no-verify",0,0)!=0;
bTrace = find_option("trace",0,0)!=0;
sCiInfo.zBranch = find_option("branch","b",1);
/* NB: the --bgcolor and --branchcolor flags still work, but are
** now undocumented, to discourage their use. --mimetype has never
** been used for anything, so also leave it undocumented */
sCiInfo.zColor = find_option("bgcolor",0,1); /* Deprecated, undocumented*/
sCiInfo.zBrClr = find_option("branchcolor",0,1); /* Deprecated, undocumented*/
sCiInfo.zMimetype = find_option("mimetype",0,1); /* Deprecated, undocumented*/
sCiInfo.closeFlag = find_option("close",0,0)!=0;
sCiInfo.integrateFlag = find_option("integrate",0,0)!=0;
sCiInfo.verboseFlag = find_option("verbose", "v", 0)!=0;
while( (zTag = find_option("tag",0,1))!=0 ){
if( zTag[0]==0 ) continue;
sCiInfo.azTag = fossil_realloc((void*)sCiInfo.azTag,
sizeof(char*)*(nTag+2));
sCiInfo.azTag[nTag++] = zTag;
sCiInfo.azTag[nTag] = 0;
}
zComFile = find_option("message-file", "M", 1);
sCiInfo.zDateOvrd = find_option("date-override",0,1);
sCiInfo.zUserOvrd = find_option("user-override",0,1);
noSign = db_get_boolean("omitsign", 0)|noSign;
if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; }
useCksum = db_get_boolean("repo-cksum", 1);
bIgnoreSkew = find_option("ignore-clock-skew",0,0)!=0;
outputManifest = db_get_manifest_setting(0);
mxSize = db_large_file_size();
if( find_option("ignore-oversize",0,0)!=0 ) mxSize = 0;
verify_all_options();
/* The --no-warnings flag and the --force flag each imply
** the --no-verify-comment flag */
if( noWarningFlag || forceFlag ){
noVerifyCom = 1;
}
/* Get the ID of the parent manifest artifact */
vid = db_lget_int("checkout", 0);
if( vid==0 ){
useCksum = 1;
if( privateFlag==0 && sCiInfo.zBranch==0 ) {
sCiInfo.zBranch=db_get("main-branch", 0);
|
| ︙ | ︙ | |||
2604 2605 2606 2607 2608 2609 2610 |
}
if( autosync_loop(syncFlags, 1, "commit") ){
fossil_exit(1);
}
}
/* So that older versions of Fossil (that do not understand delta-
| | > > | > | | | | | < | | 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 |
}
if( autosync_loop(syncFlags, 1, "commit") ){
fossil_exit(1);
}
}
/* So that older versions of Fossil (that do not understand delta-
** manifest) can continue to use this repository, and because
** delta manifests are usually a bad idea unless the repository
** has a really large number of files, do not create a new
** delta-manifest unless this repository already contains one or more
** delta-manifests, or unless the delta-manifest is explicitly requested
** by the --delta option.
**
** The forbid-delta-manifests setting prevents new delta manifests,
** even if the --delta option is used.
**
** If the remote repository sent an avoid-delta-manifests pragma on
** the autosync above, then also forbid delta manifests, even if the
** --delta option is specified. The remote repo will send the
** avoid-delta-manifests pragma if its "forbid-delta-manifests"
** setting is enabled.
*/
if( !(forceDelta || db_get_boolean("seen-delta-manifest",0))
|| db_get_boolean("forbid-delta-manifests",0)
|| g.bAvoidDeltaManifests
){
forceBaseline = 1;
}
/* Require confirmation to continue with the check-in if there is
** clock skew. This helps to prevent timewarps.
*/
if( g.clockSkewSeen ){
if( bIgnoreSkew!=0 ){
cReply = 'y';
fossil_warning("Clock skew ignored due to --ignore-clock-skew.");
}else if( !noPrompt ){
prompt_user("continue in spite of time skew (y/N)? ", &ans);
|
| ︙ | ︙ | |||
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 |
zCurBranch = branch_of_rid(vid);
}
fossil_free(zNewBranch);
/* Always exit the loop on the second pass */
if( bRecheck ) break;
/* Get the check-in comment. This might involve prompting the
** user for the check-in comment, in which case we should resync
** to renew the check-in lock and repeat the checks for conflicts.
*/
if( zComment ){
blob_zero(&comment);
blob_append(&comment, zComment, -1);
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile, ExtFILE);
blob_to_utf8_no_bom(&comment, 1);
}else if( !noPrompt ){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > | | | | | | | | | > > | | 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 |
zCurBranch = branch_of_rid(vid);
}
fossil_free(zNewBranch);
/* Always exit the loop on the second pass */
if( bRecheck ) break;
/* Figure out how much comment verification is requested */
if( noVerifyCom ){
ckComFlgs = 0;
}else{
const char *zVerComs = db_get("verify-comments","on");
if( is_false(zVerComs) ){
ckComFlgs = 0;
}else if( strcmp(zVerComs,"preview")==0 ){
ckComFlgs = COMCK_PREVIEW | COMCK_MARKUP;
}else{
ckComFlgs = COMCK_MARKUP;
}
}
/* Get the check-in comment. This might involve prompting the
** user for the check-in comment, in which case we should resync
** to renew the check-in lock and repeat the checks for conflicts.
*/
if( zComment ){
blob_zero(&comment);
blob_append(&comment, zComment, -1);
ckComFlgs &= ~COMCK_PREVIEW;
if( verify_comment(&comment, ckComFlgs) ){
fossil_fatal("Commit aborted; "
"use --no-verify-comment to override");
}
}else if( zComFile ){
blob_zero(&comment);
blob_read_from_file(&comment, zComFile, ExtFILE);
blob_to_utf8_no_bom(&comment, 1);
ckComFlgs &= ~COMCK_PREVIEW;
if( verify_comment(&comment, ckComFlgs) ){
fossil_fatal("Commit aborted; "
"use --no-verify-comment to override");
}
}else if( !noPrompt ){
while( 1/*exit-by-break*/ ){
int rc;
char *zInit;
zInit = db_text(0,"SELECT value FROM vvar WHERE name='ci-comment'");
prepare_commit_comment(&comment, zInit, &sCiInfo, vid, dryRunFlag);
db_multi_exec("REPLACE INTO vvar VALUES('ci-comment',%B)", &comment);
if( (rc = verify_comment(&comment, ckComFlgs))!=0 ){
if( rc==COMCK_PREVIEW ){
prompt_user("Continue, abort, or edit? (C/a/e)? ", &ans);
}else{
prompt_user("Edit, abort, or continue (E/a/c)? ", &ans);
}
cReply = blob_str(&ans)[0];
cReply = fossil_tolower(cReply);
blob_reset(&ans);
if( cReply=='a' ){
fossil_fatal("Commit aborted.");
}
if( cReply=='e' || (cReply!='c' && rc!=COMCK_PREVIEW) ){
fossil_free(zInit);
continue;
}
}
if( zInit && zInit[0] && fossil_strcmp(zInit, blob_str(&comment))==0 ){
prompt_user("unchanged check-in comment. continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
blob_reset(&ans);
if( cReply!='y' && cReply!='Y' ){
fossil_fatal("Commit aborted.");
}
}
fossil_free(zInit);
break;
}
db_end_transaction(0);
db_begin_transaction();
if( !g.markPrivate && vid!=0 && !allowFork && !forceFlag ){
/* Do another auto-pull, renewing the check-in lock. Then set
** bRecheck so that we loop back above to verify that the check-in
** is still not against a closed branch and still won't fork. */
int syncFlags = SYNC_PULL|SYNC_CKIN_LOCK;
|
| ︙ | ︙ |
Changes to src/checkout.c.
| ︙ | ︙ | |||
171 172 173 174 175 176 177 |
** each character as a flag to enable writing "manifest", "manifest.uuid" or
** "manifest.tags".
*/
void manifest_to_disk(int vid){
char *zManFile;
int flg;
| | | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
** each character as a flag to enable writing "manifest", "manifest.uuid" or
** "manifest.tags".
*/
void manifest_to_disk(int vid){
char *zManFile;
int flg;
flg = db_get_manifest_setting(0);
if( flg & MFESTFLG_RAW ){
Blob manifest = BLOB_INITIALIZER;
content_get(vid, &manifest);
sterilize_manifest(&manifest, CFTYPE_MANIFEST);
zManFile = mprintf("%smanifest", g.zLocalRoot);
blob_write_to_file(&manifest, zManFile);
|
| ︙ | ︙ | |||
274 275 276 277 278 279 280 | ** leaves files on disk unchanged, except the manifest and manifest.uuid ** files. ** ** The --latest flag can be used in place of VERSION to check-out the ** latest version in the repository. ** ** Options: | | | > < | > > > > > > | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
** leaves files on disk unchanged, except the manifest and manifest.uuid
** files.
**
** The --latest flag can be used in place of VERSION to check-out the
** latest version in the repository.
**
** Options:
** -f|--force Ignore edited files in the current check-out
** -k|--keep Only update the manifest file(s)
** --force-missing Force check-out even if content is missing
** --prompt Prompt before overwriting when --force is used
** --setmtime Set timestamps of all files to match their SCM-side
** times (the timestamp of the last check-in which modified
** them)
**
** See also: [[update]]
*/
void checkout_cmd(void){
int forceFlag; /* Force check-out even if edits exist */
int forceMissingFlag; /* Force check-out even if missing content */
int keepFlag; /* Do not change any files on disk */
int latestFlag; /* Check out the latest version */
char *zVers; /* Version to check out */
int promptFlag; /* True to prompt before overwriting */
int vid, prior;
int setmtimeFlag; /* --setmtime. Set mtimes on files */
Blob cksum1, cksum1b, cksum2;
db_must_be_within_tree();
db_begin_transaction();
forceMissingFlag = find_option("force-missing",0,0)!=0;
keepFlag = find_option("keep","k",0)!=0;
forceFlag = find_option("force","f",0)!=0;
latestFlag = find_option("latest",0,0)!=0;
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0;
setmtimeFlag = find_option("setmtime",0,0)!=0;
if( keepFlag != 0 ){
/* After flag collection, in order not to affect promptFlag */
forceFlag=1;
}
/* We should be done with options.. */
verify_all_options();
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){
usage("VERSION|--latest ?--force? ?--keep?");
}
|
| ︙ | ︙ |
Changes to src/clone.c.
| ︙ | ︙ | |||
127 128 129 130 131 132 133 134 135 136 137 138 139 140 | ** -B|--httpauth USER:PASS Add HTTP Basic Authorization to requests ** --nested Allow opening a repository inside an opened ** check-out ** --nocompress Omit extra delta compression ** --no-open Clone only. Do not open a check-out. ** --once Don't remember the URI. ** --private Also clone private branches ** --save-http-password Remember the HTTP password without asking ** -c|--ssh-command SSH Use SSH as the "ssh" command ** --ssl-identity FILENAME Use the SSL identity if requested by the server ** --transport-command CMD Use CMD to move messages to the server and back ** -u|--unversioned Also sync unversioned content ** -v|--verbose Show more statistics in output ** --workdir DIR Also open a check-out in DIR | > | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ** -B|--httpauth USER:PASS Add HTTP Basic Authorization to requests ** --nested Allow opening a repository inside an opened ** check-out ** --nocompress Omit extra delta compression ** --no-open Clone only. Do not open a check-out. ** --once Don't remember the URI. ** --private Also clone private branches ** --proxy PROXY Use the specified HTTP proxy ** --save-http-password Remember the HTTP password without asking ** -c|--ssh-command SSH Use SSH as the "ssh" command ** --ssl-identity FILENAME Use the SSL identity if requested by the server ** --transport-command CMD Use CMD to move messages to the server and back ** -u|--unversioned Also sync unversioned content ** -v|--verbose Show more statistics in output ** --workdir DIR Also open a check-out in DIR |
| ︙ | ︙ |
Changes to src/color.c.
| ︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
** This file contains code used to select colors based on branch and
** user names.
**
*/
#include "config.h"
#include <string.h>
#include "color.h"
/*
** Compute a hash on a branch or user name
*/
static unsigned int hash_of_name(const char *z){
unsigned int h = 0;
int i;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
** This file contains code used to select colors based on branch and
** user names.
**
*/
#include "config.h"
#include <string.h>
#include "color.h"
/*
** 140 standard CSS color names and their corresponding RGB values,
** in alphabetical order by name so that we can do a binary search
** for lookup.
*/
static const struct CssColors {
const char *zName; /* CSS Color name, lower case */
unsigned int iRGB; /* Corresponding RGB value */
} aCssColors[] = {
{ "aliceblue", 0xf0f8ff },
{ "antiquewhite", 0xfaebd7 },
{ "aqua", 0x00ffff },
{ "aquamarine", 0x7fffd4 },
{ "azure", 0xf0ffff },
{ "beige", 0xf5f5dc },
{ "bisque", 0xffe4c4 },
{ "black", 0x000000 },
{ "blanchedalmond", 0xffebcd },
{ "blue", 0x0000ff },
{ "blueviolet", 0x8a2be2 },
{ "brown", 0xa52a2a },
{ "burlywood", 0xdeb887 },
{ "cadetblue", 0x5f9ea0 },
{ "chartreuse", 0x7fff00 },
{ "chocolate", 0xd2691e },
{ "coral", 0xff7f50 },
{ "cornflowerblue", 0x6495ed },
{ "cornsilk", 0xfff8dc },
{ "crimson", 0xdc143c },
{ "cyan", 0x00ffff },
{ "darkblue", 0x00008b },
{ "darkcyan", 0x008b8b },
{ "darkgoldenrod", 0xb8860b },
{ "darkgray", 0xa9a9a9 },
{ "darkgreen", 0x006400 },
{ "darkkhaki", 0xbdb76b },
{ "darkmagenta", 0x8b008b },
{ "darkolivegreen", 0x556b2f },
{ "darkorange", 0xff8c00 },
{ "darkorchid", 0x9932cc },
{ "darkred", 0x8b0000 },
{ "darksalmon", 0xe9967a },
{ "darkseagreen", 0x8fbc8f },
{ "darkslateblue", 0x483d8b },
{ "darkslategray", 0x2f4f4f },
{ "darkturquoise", 0x00ced1 },
{ "darkviolet", 0x9400d3 },
{ "deeppink", 0xff1493 },
{ "deepskyblue", 0x00bfff },
{ "dimgray", 0x696969 },
{ "dodgerblue", 0x1e90ff },
{ "firebrick", 0xb22222 },
{ "floralwhite", 0xfffaf0 },
{ "forestgreen", 0x228b22 },
{ "fuchsia", 0xff00ff },
{ "gainsboro", 0xdcdcdc },
{ "ghostwhite", 0xf8f8ff },
{ "gold", 0xffd700 },
{ "goldenrod", 0xdaa520 },
{ "gray", 0x808080 },
{ "green", 0x008000 },
{ "greenyellow", 0xadff2f },
{ "honeydew", 0xf0fff0 },
{ "hotpink", 0xff69b4 },
{ "indianred", 0xcd5c5c },
{ "indigo", 0x4b0082 },
{ "ivory", 0xfffff0 },
{ "khaki", 0xf0e68c },
{ "lavender", 0xe6e6fa },
{ "lavenderblush", 0xfff0f5 },
{ "lawngreen", 0x7cfc00 },
{ "lemonchiffon", 0xfffacd },
{ "lightblue", 0xadd8e6 },
{ "lightcoral", 0xf08080 },
{ "lightcyan", 0xe0ffff },
{ "lightgoldenrodyellow", 0xfafad2 },
{ "lightgrey", 0xd3d3d3 },
{ "lightgreen", 0x90ee90 },
{ "lightpink", 0xffb6c1 },
{ "lightsalmon", 0xffa07a },
{ "lightseagreen", 0x20b2aa },
{ "lightskyblue", 0x87cefa },
{ "lightslategray", 0x778899 },
{ "lightsteelblue", 0xb0c4de },
{ "lightyellow", 0xffffe0 },
{ "lime", 0x00ff00 },
{ "limegreen", 0x32cd32 },
{ "linen", 0xfaf0e6 },
{ "magenta", 0xff00ff },
{ "maroon", 0x800000 },
{ "mediumaquamarine", 0x66cdaa },
{ "mediumblue", 0x0000cd },
{ "mediumorchid", 0xba55d3 },
{ "mediumpurple", 0x9370d8 },
{ "mediumseagreen", 0x3cb371 },
{ "mediumslateblue", 0x7b68ee },
{ "mediumspringgreen", 0x00fa9a },
{ "mediumturquoise", 0x48d1cc },
{ "mediumvioletred", 0xc71585 },
{ "midnightblue", 0x191970 },
{ "mintcream", 0xf5fffa },
{ "mistyrose", 0xffe4e1 },
{ "moccasin", 0xffe4b5 },
{ "navajowhite", 0xffdead },
{ "navy", 0x000080 },
{ "oldlace", 0xfdf5e6 },
{ "olive", 0x808000 },
{ "olivedrab", 0x6b8e23 },
{ "orange", 0xffa500 },
{ "orangered", 0xff4500 },
{ "orchid", 0xda70d6 },
{ "palegoldenrod", 0xeee8aa },
{ "palegreen", 0x98fb98 },
{ "paleturquoise", 0xafeeee },
{ "palevioletred", 0xd87093 },
{ "papayawhip", 0xffefd5 },
{ "peachpuff", 0xffdab9 },
{ "peru", 0xcd853f },
{ "pink", 0xffc0cb },
{ "plum", 0xdda0dd },
{ "powderblue", 0xb0e0e6 },
{ "purple", 0x800080 },
{ "red", 0xff0000 },
{ "rosybrown", 0xbc8f8f },
{ "royalblue", 0x4169e1 },
{ "saddlebrown", 0x8b4513 },
{ "salmon", 0xfa8072 },
{ "sandybrown", 0xf4a460 },
{ "seagreen", 0x2e8b57 },
{ "seashell", 0xfff5ee },
{ "sienna", 0xa0522d },
{ "silver", 0xc0c0c0 },
{ "skyblue", 0x87ceeb },
{ "slateblue", 0x6a5acd },
{ "slategray", 0x708090 },
{ "snow", 0xfffafa },
{ "springgreen", 0x00ff7f },
{ "steelblue", 0x4682b4 },
{ "tan", 0xd2b48c },
{ "teal", 0x008080 },
{ "thistle", 0xd8bfd8 },
{ "tomato", 0xff6347 },
{ "turquoise", 0x40e0d0 },
{ "violet", 0xee82ee },
{ "wheat", 0xf5deb3 },
{ "white", 0xffffff },
{ "whitesmoke", 0xf5f5f5 },
{ "yellow", 0xffff00 },
{ "yellowgreen", 0x9acd32 },
};
/*
** Attempt to translate a CSS color name into an integer that
** represents the equivalent RGB value. Ignore alpha if provided.
** If the name cannot be translated, return -1.
*/
int color_name_to_rgb(const char *zName){
if( zName==0 || zName[0]==0 ) return -1;
if( zName[0]=='#' ){
int i, v = 0;
for(i=1; i<=6 && fossil_isxdigit(zName[i]); i++){
v = v*16 + fossil_hexvalue(zName[i]);
}
if( i==4 ){
v = fossil_hexvalue(zName[1])*0x110000 +
fossil_hexvalue(zName[2])*0x1100 +
fossil_hexvalue(zName[3])*0x11;
return v;
}
if( i==7 ){
return v;
}
return -1;
}else{
int iMin = 0;
int iMax = count(aCssColors)-1;
while( iMin<=iMax ){
int iMid = (iMin+iMax)/2;
int c = sqlite3_stricmp(aCssColors[iMid].zName, zName);
if( c==0 ) return aCssColors[iMid].iRGB;
if( c<0 ){
iMin = iMid+1;
}else{
iMax = iMid-1;
}
}
return -1;
}
}
/*
** SETTING: raw-bgcolor boolean default=off
**
** Fossil usually tries to adjust user-specified background colors
** for checkins so that the text is readable and so that the color
** is not too garish. This setting disables that filter. When
** this setting is on, the user-selected background colors are shown
** exactly as requested.
*/
/*
** Shift a color provided by the user so that it is suitable
** for use as a background color in the current skin.
**
** The return value is a #HHHHHH color name contained in
** static space that is overwritten on the next call.
**
** If we cannot make sense of the background color recommendation
** that is the input, then return NULL.
**
** The iFgClr parameter is normally 0. But for testing purposes, set
** it to 1 for a black foregrounds and 2 for a white foreground.
*/
const char *reasonable_bg_color(const char *zRequested, int iFgClr){
int iRGB = color_name_to_rgb(zRequested);
int r, g, b; /* RGB components of requested color */
static int systemFg = 0; /* 1==black-foreground 2==white-foreground */
int fg; /* Foreground color to actually use */
static char zColor[10]; /* Return value */
if( iFgClr ){
fg = iFgClr;
}else if( systemFg==0 ){
if( db_get_boolean("raw-bgcolor",0) ){
fg = systemFg = 3;
}else{
fg = systemFg = skin_detail_boolean("white-foreground") ? 2 : 1;
}
}else{
fg = systemFg;
}
if( fg>=3 ) return zRequested;
if( iRGB<0 ) return 0;
r = (iRGB>>16) & 0xff;
g = (iRGB>>8) & 0xff;
b = iRGB & 0xff;
if( fg==1 ){
const int K = 70;
r = (K*r)/255 + (255-K);
g = (K*g)/255 + (255-K);
b = (K*b)/255 + (255-K);
}else{
const int K = 90;
r = (K*r)/255;
g = (K*g)/255;
b = (K*b)/255;
}
sqlite3_snprintf(8, zColor, "#%02x%02x%02x", r,g,b);
return zColor;
}
/*
** Compute a hash on a branch or user name
*/
static unsigned int hash_of_name(const char *z){
unsigned int h = 0;
int i;
|
| ︙ | ︙ | |||
183 184 185 186 187 188 189 |
@ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br>
}
@ <input type="submit" value="Submit">
@ <input type="submit" name="rand" value="Random">
@ </form>
style_finish_page();
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
@ <input type="text" size="30" name='%s(zNm)' value='%h(PD(zNm,""))'><br>
}
@ <input type="submit" value="Submit">
@ <input type="submit" name="rand" value="Random">
@ </form>
style_finish_page();
}
/*
** WEBPAGE: test-bgcolor
**
** Show how user-specified background colors will be rendered
** using the reasonable_bg_color() algorithm.
*/
void test_bgcolor_page(void){
const char *zReq; /* Requested color name */
const char *zBG; /* Actual color provided */
const char *zBg1;
char zNm[10];
static const char *azDflt[] = {
"red", "orange", "yellow", "green", "blue", "indigo", "violet",
"tan", "brown", "gray"
};
int i, cnt, iClr, r, g, b;
char *zFg;
login_check_credentials();
style_set_current_feature("test");
style_header("Background Color Test");
for(i=cnt=0; i<10; i++){
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
zReq = PD(zNm,azDflt[i]);
if( zReq==0 || zReq[0]==0 ) continue;
if( cnt==0 ){
@ <table border="1" cellspacing="0" cellpadding="10">
@ <tr>
@ <th>Requested Background
@ <th>Light mode
@ <th>Dark mode
@ </tr>
}
cnt++;
zBG = reasonable_bg_color(zReq, 0);
if( zBG==0 ){
@ <tr><td colspan="3" align="center">\
@ "%h(zReq)" is not a recognized color name</td></tr>
continue;
}
iClr = color_name_to_rgb(zReq);
r = (iClr>>16) & 0xff;
g = (iClr>>8) & 0xff;
b = iClr & 0xff;
if( 3*r + 7*g + b > 6*255 ){
zFg = "black";
}else{
zFg = "white";
}
if( zReq[0]!='#' ){
char zReqRGB[12];
sqlite3_snprintf(sizeof(zReqRGB),zReqRGB,"#%06x",color_name_to_rgb(zReq));
@ <tr><td style='color:%h(zFg);background-color:%h(zReq);'>\
@ Requested color "%h(zReq)" (%h(zReqRGB))</td>
}else{
@ <tr><td style='color:%h(zFg);background-color:%s(zReq);'>\
@ Requested color "%h(zReq)"</td>
}
zBg1 = reasonable_bg_color(zReq,1);
@ <td style='color:black;background-color:%h(zBg1);'>\
@ Background color for dark text: %h(zBg1)</td>
zBg1 = reasonable_bg_color(zReq,2);
@ <td style='color:white;background-color:%h(zBg1);'>\
@ Background color for light text: %h(zBg1)</td></tr>
}
if( cnt ){
@ </table>
@ <hr>
}
@ <form method="POST">
@ <p>Enter CSS color names below and see them shifted into corresponding
@ background colors above.</p>
for(i=0; i<10; i++){
sqlite3_snprintf(sizeof(zNm),zNm,"b%d",i);
@ <input type="text" size="30" name='%s(zNm)' \
@ value='%h(PD(zNm,azDflt[i]))'><br>
}
@ <input type="submit" value="Submit">
@ </form>
style_finish_page();
}
|
Changes to src/comformat.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 | ** text on a TTY. */ #include "config.h" #include "comformat.h" #include <assert.h> #if INTERFACE | | > > > | > > > < < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
** text on a TTY.
*/
#include "config.h"
#include "comformat.h"
#include <assert.h>
#if INTERFACE
#define COMMENT_PRINT_NONE ((u32)0x00000000) /* No flags */
#define COMMENT_PRINT_CANONICAL ((u32)0x00000001) /* Use canonical algorithm */
#define COMMENT_PRINT_DEFAULT COMMENT_PRINT_CANONICAL /* Default */
#define COMMENT_PRINT_UNSET (-1) /* Not initialized */
/* The canonical comment printing algorithm is recommended. We make
** no promise of on-going support for any of the following flags:
*/
#define COMMENT_PRINT_TRIM_CRLF ((u32)0x00000002) /* Trim leading CR/LF. */
#define COMMENT_PRINT_TRIM_SPACE ((u32)0x00000004) /* Trim leading/trailing. */
#define COMMENT_PRINT_WORD_BREAK ((u32)0x00000008) /* Break lines on words. */
#define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
#endif
/********* Code copied from SQLite src/shell.c.in on 2024-09-30 **********/
/* Lookup table to estimate the number of columns consumed by a Unicode
** character.
*/
static const struct {
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
const char *zLine, /* [in] The comment line being printed. */
int index, /* [in] The current character index being handled. */
int maxChars, /* [in] Optimization hint to abort before space found. */
int *sumWidth /* [out] Summated width of all characters to next space. */
){
int cchUTF8, utf32, wcwidth = 0;
int nextIndex = index;
for(;;){
char_info_utf8(&zLine[nextIndex],&cchUTF8,&utf32);
nextIndex += cchUTF8;
wcwidth += cli_wcwidth(utf32);
if( zLine[nextIndex]==0 || fossil_isspace(zLine[nextIndex]) ||
wcwidth>maxChars ){
*sumWidth = wcwidth;
return nextIndex;
}
}
return 0; /* NOT REACHED */
}
/*
| > | > > | > > | | | | | | | > > > | | | > > > > > > > > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
const char *zLine, /* [in] The comment line being printed. */
int index, /* [in] The current character index being handled. */
int maxChars, /* [in] Optimization hint to abort before space found. */
int *sumWidth /* [out] Summated width of all characters to next space. */
){
int cchUTF8, utf32, wcwidth = 0;
int nextIndex = index;
if( zLine[index]==0 ) return index;
for(;;){
char_info_utf8(&zLine[nextIndex],&cchUTF8,&utf32);
nextIndex += cchUTF8;
wcwidth += cli_wcwidth(utf32);
if( zLine[nextIndex]==0 || fossil_isspace(zLine[nextIndex]) ||
wcwidth>maxChars ){
*sumWidth = wcwidth;
return nextIndex;
}
}
return 0; /* NOT REACHED */
}
/*
** Return information about the next (single- or multi-byte) character in
** z[0]. Two values are computed:
**
** * The number of bytes needed to represent the character.
** * The UTF code point value.
**
** Incomplete, ill-formed and overlong sequences are consumed together as
** one invalid code point. The invalid lead bytes 0xC0 to 0xC1 and 0xF5 to
** 0xF7 are allowed to initiate (ill-formed) 2- and 4-byte sequences,
** respectively, the other invalid lead bytes 0xF8 to 0xFF are treated
** as invalid 1-byte sequences (as lone trail bytes), all resulting
** in one invalid code point. Invalid UTF-8 sequences encoding a
** non-scalar code point (UTF-16 surrogates U+D800 to U+DFFF) are allowed.
**
** ANSI escape sequences of the form "\033[...X" are interpreted as a
** zero-width character.
*/
void char_info_utf8(
const char *z, /* The character to be analyzed */
int *pCchUTF8, /* OUT: The number of bytes used by this character */
int *pUtf32 /* OUT: The UTF8 code point (used to determine width) */
){
int i = 0; /* Counted bytes. */
int cchUTF8 = 1; /* Code units consumed. */
int maxUTF8 = 1; /* Expected sequence length. */
char c = z[i++];
if( c==0x1b && z[i]=='[' ){
i++;
while( z[i]>=0x30 && z[i]<=0x3f ){ i++; }
while( z[i]>=0x20 && z[i]<=0x2f ){ i++; }
if( z[i]>=0x40 && z[i]<=0x7e ){
*pCchUTF8 = i+1;
*pUtf32 = 0x301; /* A zero-width character */
return;
}
}
if( (c&0x80)==0x00 ){ /* 7-bit ASCII character. */
*pCchUTF8 = 1;
*pUtf32 = (int)z[0];
return;
}
else if( (c&0xe0)==0xc0 ) maxUTF8 = 2; /* UTF-8 lead byte 110vvvvv */
else if( (c&0xf0)==0xe0 ) maxUTF8 = 3; /* UTF-8 lead byte 1110vvvv */
|
| ︙ | ︙ | |||
463 464 465 466 467 468 469 |
}
if( pzLine ){
*pzLine = zLine + index;
}
}
/*
| | | > | > > > > > > > | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
}
if( pzLine ){
*pzLine = zLine + index;
}
}
/*
** This is the canonical comment printing algorithm. This is the algorithm
** that is recommended and that is used unless the administrator has made
** special arrangements to use a customized algorithm.
**
** Given a comment string, format that string for printing on a TTY.
** Assume that the output cursor is indent spaces from the left margin
** and that a single line can contain no more than 'width' characters.
** Indent all subsequent lines by 'indent'.
**
** Formatting features:
**
** * Leading whitespace is removed.
** * Internal whitespace sequences are changed into a single space (0x20)
** character.
** * Lines are broken at a space, or at a hyphen ("-") whenever possible.
**
** Returns the number of new lines emitted.
*/
static int comment_print_canonical(
const char *zText, /* The comment text to be printed. */
int indent, /* Number of spaces to indent each non-initial line. */
int width /* Maximum number of characters per line. */
){
int maxChars = width - indent;
int si, sk, i, k, kc;
int doIndent = 0;
|
| ︙ | ︙ | |||
562 563 564 565 566 567 568 | /* ** This is the comment printing function. The comment printing algorithm ** contained within it attempts to preserve the formatting present within ** the comment string itself while honoring line width limitations. There ** are several flags that modify the default behavior of this function: ** | | > > > > | > | | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | /* ** This is the comment printing function. The comment printing algorithm ** contained within it attempts to preserve the formatting present within ** the comment string itself while honoring line width limitations. There ** are several flags that modify the default behavior of this function: ** ** COMMENT_PRINT_CANONICAL: Use the canonical printing algorithm: ** * Omit leading and trailing whitespace ** * Collapse internal whitespace into a ** single space (0x20) character. ** * Attempt to break lines at whitespace ** or hyphens. ** This is the recommended algorithm and is ** used in most cases. ** ** COMMENT_PRINT_TRIM_CRLF: Trims leading and trailing carriage-returns ** and line-feeds where they do not materially ** impact pre-existing formatting (i.e. at the ** start of the comment string -AND- right ** before line indentation). This flag does ** not apply to the legacy comment printing |
| ︙ | ︙ | |||
611 612 613 614 615 616 617 |
const char *zText, /* The comment text to be printed. */
const char *zOrigText, /* Original comment text ONLY, may be NULL. */
int indent, /* Spaces to indent each non-initial line. */
int width, /* Maximum number of characters per line. */
int flags /* Zero or more "COMMENT_PRINT_*" flags. */
){
int maxChars = width - indent;
| > | > > > > > > > | | | | | | < < < | | | | | | | | | | | | | | | | | | | | | | | | | > < | | | | 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 |
const char *zText, /* The comment text to be printed. */
const char *zOrigText, /* Original comment text ONLY, may be NULL. */
int indent, /* Spaces to indent each non-initial line. */
int width, /* Maximum number of characters per line. */
int flags /* Zero or more "COMMENT_PRINT_*" flags. */
){
int maxChars = width - indent;
if( flags & COMMENT_PRINT_CANONICAL ){
/* Use the canonical algorithm. This is what happens in almost
** all cases. */
return comment_print_canonical(zText, indent, width);
}else{
/* The remaining is a more complex formatting algorithm that is very
** seldom used and is considered deprecated.
*/
int trimCrLf = flags & COMMENT_PRINT_TRIM_CRLF;
int trimSpace = flags & COMMENT_PRINT_TRIM_SPACE;
int wordBreak = flags & COMMENT_PRINT_WORD_BREAK;
int origBreak = flags & COMMENT_PRINT_ORIG_BREAK;
int lineCnt = 0;
const char *zLine;
if( width<0 ){
comment_set_maxchars(indent, &maxChars);
}
if( zText==0 ) zText = "(NULL)";
if( maxChars<=0 ){
maxChars = strlen(zText);
}
if( trimSpace ){
while( fossil_isspace(zText[0]) ){ zText++; }
}
if( zText[0]==0 ){
fossil_print("\n");
lineCnt++;
return lineCnt;
}
zLine = zText;
for(;;){
comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
&lineCnt, &zLine);
if( zLine==0 ) break;
while( fossil_isspace(zLine[0]) ) zLine++;
if( zLine[0]==0 ) break;
}
return lineCnt;
}
}
/*
** Return the "COMMENT_PRINT_*" flags specified by the following sources,
** evaluated in the following cascading order:
**
** 1. The local (per-repository) "comment-format" setting.
** 2. The global (all-repositories) "comment-format" setting.
** 3. The default value COMMENT_PRINT_DEFAULT.
*/
int get_comment_format(){
int comFmtFlags;
/* We must cache this result, else running the timeline can end up
** querying the comment-format setting from the global db once per
** timeline entry, which brings it to a crawl if that db is
|
| ︙ | ︙ | |||
687 688 689 690 691 692 693 | return g.comFmtFlags; } /* ** ** COMMAND: test-comment-format ** | | > > > > > > > > > > < < | | < < < < | | | > > > | > > > > | | | | | > | | > | | | > > > < < < < < < < < | < | > | > | | | | > > > > > > > > > > > > > > > < < | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 |
return g.comFmtFlags;
}
/*
**
** COMMAND: test-comment-format
**
** Usage: %fossil test-comment-format [OPTIONS] TEXT [PREFIX] [ORIGTEXT]
**
** Test comment formatting and printing. Use for testing only.
**
** The default (canonical) formatting algorithm is:
**
** * Omit leading/trailing whitespace
** * Collapse internal whitespace into a single space character.
** * Attempt to break lines at whitespace or at a hyphen.
**
** Use --whitespace, --origbreak, --trimcrlf, --trimspace,
** and/or --wordbreak to disable the canonical processing and do
** the special processing specified by those other options.
**
** Options:
** --decode Decode the text using the same method used when
** handling the value of a C-card from a manifest.
** --file FILE Omit the TEXT argument and read the comment text
** from FILE.
** --indent Number of spaces to indent (default (-1) is to
** auto-detect). Zero means no indent.
** --orig FILE Take the value for the ORIGTEXT argumetn from FILE.
** --origbreak Attempt to break when the original comment text
** is detected.
** --trimcrlf Enable trimming of leading/trailing CR/LF.
** --trimspace Enable trimming of leading/trailing spaces.
** --whitespace Keep all internal whitespace.
** --wordbreak Attempt to break lines on word boundaries.
** -W|--width NUM Width of lines (default (-1) is to auto-detect).
** Zero means no limit.
*/
void test_comment_format(void){
const char *zWidth;
const char *zIndent;
const char *zPrefix = 0;
char *zText = 0;
char *zOrigText = 0;
int indent, width;
int i;
const char *fromFile = find_option("file", 0, 1);
int decode = find_option("decode", 0, 0)!=0;
int flags = COMMENT_PRINT_CANONICAL;
const char *fromOrig = find_option("orig", 0, 1);
if( find_option("whitespace",0,0) ){
flags = 0;
}
if( find_option("trimcrlf", 0, 0) ){
flags = COMMENT_PRINT_TRIM_CRLF;
}
if( find_option("trimspace", 0, 0) ){
flags |= COMMENT_PRINT_TRIM_SPACE;
flags &= COMMENT_PRINT_CANONICAL;
}
if( find_option("wordbreak", 0, 0) ){
flags |= COMMENT_PRINT_WORD_BREAK;
flags &= COMMENT_PRINT_CANONICAL;
}
if( find_option("origbreak", 0, 0) ){
flags |= COMMENT_PRINT_ORIG_BREAK;
flags &= COMMENT_PRINT_CANONICAL;
}
zWidth = find_option("width","W",1);
if( zWidth ){
width = atoi(zWidth);
}else{
width = -1; /* automatic */
}
zIndent = find_option("indent",0,1);
if( zIndent ){
indent = atoi(zIndent);
}else{
indent = -1; /* automatic */
}
verify_all_options();
zPrefix = zText = zOrigText = 0;
if( fromFile ){
Blob fileData;
blob_read_from_file(&fileData, fromFile, ExtFILE);
zText = mprintf("%s", blob_str(&fileData));
blob_reset(&fileData);
}
if( fromOrig ){
Blob fileData;
blob_read_from_file(&fileData, fromOrig, ExtFILE);
zOrigText = mprintf("%s", blob_str(&fileData));
blob_reset(&fileData);
}
for(i=2; i<g.argc; i++){
if( zText==0 ){
zText = g.argv[i];
continue;
}
if( zPrefix==0 ){
zPrefix = g.argv[i];
continue;
}
if( zOrigText==0 ){
zOrigText = g.argv[i];
continue;
}
usage("[OPTIONS] TEXT [PREFIX] [ORIGTEXT]");
}
if( decode ){
zText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zText);
defossilize(zText);
if( zOrigText ){
zOrigText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zOrigText);
defossilize(zOrigText);
}
}
if( zPrefix==0 ) zPrefix = "00:00:00 ";
if( indent<0 ){
indent = strlen(zPrefix);
}
if( zPrefix && *zPrefix ){
fossil_print("%s", zPrefix);
}
fossil_print("(%d lines output)\n",
comment_print(zText, zOrigText, indent, width, flags));
}
|
Changes to src/configure.c.
| ︙ | ︙ | |||
98 99 100 101 102 103 104 |
{ "default-skin", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "icon-mimetype", CONFIGSET_SKIN },
{ "icon-image", CONFIGSET_SKIN },
| < | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
{ "default-skin", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "icon-mimetype", CONFIGSET_SKIN },
{ "icon-image", CONFIGSET_SKIN },
{ "timeline-date-format", CONFIGSET_SKIN },
{ "timeline-default-style", CONFIGSET_SKIN },
{ "timeline-dwelltime", CONFIGSET_SKIN },
{ "timeline-closetime", CONFIGSET_SKIN },
{ "timeline-hard-newlines", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
|
| ︙ | ︙ | |||
815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
**
** > fossil configuration sync AREA ?URL?
**
** Synchronize configuration changes in the local repository with
** the remote repository at URL.
**
** Options:
** -R|--repository REPO Affect repository REPO with changes
**
** See also: [[settings]], [[unset]]
*/
void configuration_cmd(void){
int n;
const char *zMethod;
| > > | 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 |
**
** > fossil configuration sync AREA ?URL?
**
** Synchronize configuration changes in the local repository with
** the remote repository at URL.
**
** Options:
** --proxy PROXY Use PROXY as http proxy during sync operation
** (used by pull, push and sync subcommands)
** -R|--repository REPO Affect repository REPO with changes
**
** See also: [[settings]], [[unset]]
*/
void configuration_cmd(void){
int n;
const char *zMethod;
|
| ︙ | ︙ | |||
887 888 889 890 891 892 893 894 895 896 897 898 899 900 |
if( g.argc==5 ){
zServer = g.argv[4];
}
url_parse(zServer, URL_PROMPT_PW|URL_USE_CONFIG);
if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
user_select();
url_enable_proxy("via proxy: ");
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
if( strncmp(zMethod, "push", n)==0 ){
client_sync(0,0,(unsigned)mask,0,0);
}else if( strncmp(zMethod, "pull", n)==0 ){
if( overwriteFlag ) db_unprotect(PROTECT_USER);
client_sync(0,(unsigned)mask,0,0,0);
if( overwriteFlag ) db_protect_pop();
| > | 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 |
if( g.argc==5 ){
zServer = g.argv[4];
}
url_parse(zServer, URL_PROMPT_PW|URL_USE_CONFIG);
if( g.url.protocol==0 ) fossil_fatal("no server URL specified");
user_select();
url_enable_proxy("via proxy: ");
g.zHttpAuth = get_httpauth();
if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE;
if( strncmp(zMethod, "push", n)==0 ){
client_sync(0,0,(unsigned)mask,0,0);
}else if( strncmp(zMethod, "pull", n)==0 ){
if( overwriteFlag ) db_unprotect(PROTECT_USER);
client_sync(0,(unsigned)mask,0,0,0);
if( overwriteFlag ) db_protect_pop();
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 |
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
url_nouser_func,0,0);
sqlite3_create_function(db, "chat_msg_from_event", 4,
SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
chat_msg_from_event, 0, 0);
sqlite3_create_function(db, "inode", 1, SQLITE_UTF8, 0,
file_inode_sql_func,0,0);
}
#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
| > > | 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
sqlite3_create_function(db, "url_nouser", 1, SQLITE_UTF8, 0,
url_nouser_func,0,0);
sqlite3_create_function(db, "chat_msg_from_event", 4,
SQLITE_UTF8 | SQLITE_INNOCUOUS, 0,
chat_msg_from_event, 0, 0);
sqlite3_create_function(db, "inode", 1, SQLITE_UTF8, 0,
file_inode_sql_func,0,0);
sqlite3_create_function(db, "artifact_to_json", 1, SQLITE_UTF8, 0,
artifact_to_json_sql_func,0,0);
}
#if USE_SEE
/*
** This is a pointer to the saved database encryption key string.
*/
|
| ︙ | ︙ | |||
3202 3203 3204 3205 3206 3207 3208 |
Blob hash;
Blob manifest;
db_unprotect(PROTECT_ALL);
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA_MAX, 0);
db_set("rebuilt", get_version(), 0);
| < < < < < < < | 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 |
Blob hash;
Blob manifest;
db_unprotect(PROTECT_ALL);
db_set("content-schema", CONTENT_SCHEMA, 0);
db_set("aux-schema", AUX_SCHEMA_MAX, 0);
db_set("rebuilt", get_version(), 0);
db_multi_exec(
"INSERT INTO config(name,value,mtime)"
" VALUES('server-code', lower(hex(randomblob(20))),now());"
"INSERT INTO config(name,value,mtime)"
" VALUES('project-code', lower(hex(randomblob(20))),now());"
);
db_create_default_users(0, zDefaultUser);
if( zDefaultUser ) g.zLogin = zDefaultUser;
user_select();
if( zTemplate ){
/*
** Copy all settings from the supplied template repository.
|
| ︙ | ︙ | |||
3645 3646 3647 3648 3649 3650 3651 3652 | ** Return the text of the string if it is found. Return NULL if not ** found. ** ** If the zNonVersionedSetting parameter is not NULL then it holds the ** non-versioned value for this setting. If both a versioned and a ** non-versioned value exist and are not equal, then a warning message ** might be generated. */ | > > > > > > > | > > > > | > > > > | | | | | | | | > > | | < < | < > > | | > | | | < < < < < | | | | | | | | | | | > > > | | | | | | > > | | > > > > | 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 |
** Return the text of the string if it is found. Return NULL if not
** found.
**
** If the zNonVersionedSetting parameter is not NULL then it holds the
** non-versioned value for this setting. If both a versioned and a
** non-versioned value exist and are not equal, then a warning message
** might be generated.
**
** zCkin is normally NULL. In that case, the versioned setting is
** take from the local check-out, if a local checkout exists, or from
** checkin named by the g.zOpenRevision global variable. If zCkin is
** not NULL, then zCkin is the name of the specific checkin from which
** versioned setting value is taken. When zCkin is not NULL, the cache
** is bypassed.
*/
char *db_get_versioned(
const char *zName,
char *zNonVersionedSetting,
const char *zCkin
){
char *zVersionedSetting = 0;
int noWarn = 0;
int found = 0;
struct _cacheEntry {
struct _cacheEntry *next;
const char *zName, *zValue;
} *cacheEntry = 0;
static struct _cacheEntry *cache = 0;
if( !g.localOpen && g.zOpenRevision==0 && zCkin==0 ){
return zNonVersionedSetting;
}
/* Look up name in cache */
if( zCkin==0 ){
cacheEntry = cache;
while( cacheEntry!=0 ){
if( fossil_strcmp(cacheEntry->zName, zName)==0 ){
zVersionedSetting = fossil_strdup(cacheEntry->zValue);
break;
}
cacheEntry = cacheEntry->next;
}
}
/* Attempt to read value from file in check-out if there wasn't a cache hit.*/
if( cacheEntry==0 ){
Blob versionedPathname;
Blob setting;
blob_init(&versionedPathname, 0, 0);
blob_init(&setting, 0, 0);
if( !g.localOpen || zCkin!=0 ){
/* Repository is in the process of being opened, but files have not been
* written to disk. Load from the database. */
blob_appendf(&versionedPathname, ".fossil-settings/%s", zName);
if( historical_blob(zCkin ? zCkin : g.zOpenRevision,
blob_str(&versionedPathname),
&setting, 0)
){
found = 1;
}
}else{
blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
g.zLocalRoot, zName);
if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){
/* File exists, and contains the value for this setting. Load from
** the file. */
const char *zFile = blob_str(&versionedPathname);
if( blob_read_from_file(&setting, zFile, ExtFILE)>=0 ){
found = 1;
}
/* See if there's a no-warn flag */
blob_append(&versionedPathname, ".no-warn", -1);
if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){
noWarn = 1;
}
}
}
blob_reset(&versionedPathname);
if( found ){
blob_strip_comment_lines(&setting, &setting);
blob_trim(&setting); /* Avoid non-obvious problems with line endings
** on boolean properties */
zVersionedSetting = fossil_strdup(blob_str(&setting));
}
blob_reset(&setting);
/* Store result in cache, which can be the value or 0 if not found */
if( zCkin==0 ){
cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(*cacheEntry));
cacheEntry->next = cache;
cacheEntry->zName = zName;
cacheEntry->zValue = fossil_strdup(zVersionedSetting);
cache = cacheEntry;
}
}
/* Display a warning? */
if( zVersionedSetting!=0
&& zNonVersionedSetting!=0
&& zNonVersionedSetting[0]!='\0'
&& zCkin==0
&& !noWarn
){
/* There's a versioned setting, and a non-versioned setting. Tell
** the user about the conflict */
fossil_warning(
"setting %s has both versioned and non-versioned values: using "
"versioned value from file \"%/.fossil-settings/%s\" (to silence "
"this warning, either create an empty file named "
"\"%/.fossil-settings/%s.no-warn\" in the check-out root, or delete "
"the non-versioned setting with \"fossil unset %s\")", zName,
g.zLocalRoot, zName, g.zLocalRoot, zName, zName
);
}
/* Prefer the versioned setting */
return ( zVersionedSetting!=0 ) ? zVersionedSetting : zNonVersionedSetting;
}
/*
** Get and set values from the CONFIG, GLOBAL_CONFIG and VVAR table in the
|
| ︙ | ︙ | |||
3776 3777 3778 3779 3780 3781 3782 |
}
db_reset(&q2);
}
if( pSetting!=0 && pSetting->versionable ){
/* This is a versionable setting, try and get the info from a
** checked-out file */
char * zZ = z;
| | | 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 |
}
db_reset(&q2);
}
if( pSetting!=0 && pSetting->versionable ){
/* This is a versionable setting, try and get the info from a
** checked-out file */
char * zZ = z;
z = db_get_versioned(zName, z, 0);
if(zZ != z){
fossil_free(zZ);
}
}
if( z==0 ){
if( zDefault==0 && pSetting && pSetting->def[0] ){
z = fossil_strdup(pSetting->def);
|
| ︙ | ︙ | |||
3917 3918 3919 3920 3921 3922 3923 |
}else if( is_false(zVal) ){
dflt = 0;
}
fossil_free(zVal);
return dflt;
}
int db_get_versioned_boolean(const char *zName, int dflt){
| | | 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 |
}else if( is_false(zVal) ){
dflt = 0;
}
fossil_free(zVal);
return dflt;
}
int db_get_versioned_boolean(const char *zName, int dflt){
char *zVal = db_get_versioned(zName, 0, 0);
if( zVal==0 ) return dflt;
if( is_truth(zVal) ) return 1;
if( is_false(zVal) ) return 0;
return dflt;
}
char *db_lget(const char *zName, const char *zDefault){
return db_text(zDefault,
|
| ︙ | ︙ | |||
4046 4047 4048 4049 4050 4051 4052 4053 | /* ** Get the manifest setting. For backwards compatibility first check if the ** value is a boolean. If it's not a boolean, treat each character as a flag ** to enable a manifest type. This system puts certain boundary conditions on ** which letters can be used to represent flags (any permutation of flags must ** not be able to fully form one of the boolean values). */ | > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 |
/*
** Get the manifest setting. For backwards compatibility first check if the
** value is a boolean. If it's not a boolean, treat each character as a flag
** to enable a manifest type. This system puts certain boundary conditions on
** which letters can be used to represent flags (any permutation of flags must
** not be able to fully form one of the boolean values).
**
** "manifest" is a versionable setting. But we do not issue a warning
** if there is a conflict. Instead, the value returned is the value for
** the versioned setting if the versioned setting exists, or the ordinary
** setting otherwise.
**
** The argument zCkin is the specific check-in for which we want the
** manifest setting.
*/
int db_get_manifest_setting(const char *zCkin){
int flg;
char *zVal;
/* Look for the versioned setting first */
zVal = db_get_versioned("manifest", 0, zCkin);
if( zVal==0 && g.repositoryOpen ){
/* No versioned setting, look for the repository setting second */
zVal = db_text(0, "SELECT value FROM config WHERE name='manifest'");
}
if( zVal==0 || is_false(zVal) ){
return 0;
}else if( is_truth(zVal) ){
return MFESTFLG_RAW|MFESTFLG_UUID;
}
flg = 0;
while( *zVal ){
switch( *zVal ){
case 'r': flg |= MFESTFLG_RAW; break;
case 'u': flg |= MFESTFLG_UUID; break;
case 't': flg |= MFESTFLG_TAGS; break;
}
zVal++;
}
return flg;
}
/*
** COMMAND: test-manifest-setting
**
** Usage: %fossil test-manifest-setting VERSION VERSION ...
**
** Display the value for the "manifest" setting for various versions
** of the repository.
*/
void test_manfest_setting_cmd(void){
int i;
db_find_and_open_repository(0, 0);
for(i=2; i<g.argc; i++){
int m = db_get_manifest_setting(g.argv[i]);
fossil_print("%s:\n", g.argv[i]);
fossil_print(" flags = 0x%02x\n", m);
if( m & MFESTFLG_RAW ){
fossil_print(" manifest\n");
}
if( m & MFESTFLG_UUID ){
fossil_print(" manifest.uuid\n");
}
if( m & MFESTFLG_TAGS ){
fossil_print(" manifest.tags\n");
}
}
}
/*
** Record the name of a local repository in the global_config() database.
** The repository filename %s is recorded as an entry with a "name" field
** of the following form:
**
|
| ︙ | ︙ | |||
4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 | ** -f|--force Continue with the open even if the working directory is ** not empty, or if auto-sync fails. ** --force-missing Force opening a repository with missing content ** -k|--keep Only modify the manifest file(s) ** --nested Allow opening a repository inside an opened check-out ** --nosync Do not auto-sync the repository prior to opening even ** if the autosync setting is on. ** --repodir DIR If REPOSITORY is a URI that will be cloned, store ** the clone in DIR rather than in "." ** --setmtime Set timestamps of all files to match their SCM-side ** times (the timestamp of the last check-in which modified ** them). ** --verbose If passed a URI then this flag is passed on to the clone ** operation, otherwise it has no effect | > | 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 | ** -f|--force Continue with the open even if the working directory is ** not empty, or if auto-sync fails. ** --force-missing Force opening a repository with missing content ** -k|--keep Only modify the manifest file(s) ** --nested Allow opening a repository inside an opened check-out ** --nosync Do not auto-sync the repository prior to opening even ** if the autosync setting is on. ** --proxy PROXY Use PROXY as http proxy during sync operation ** --repodir DIR If REPOSITORY is a URI that will be cloned, store ** the clone in DIR rather than in "." ** --setmtime Set timestamps of all files to match their SCM-side ** times (the timestamp of the last check-in which modified ** them). ** --verbose If passed a URI then this flag is passed on to the clone ** operation, otherwise it has no effect |
| ︙ | ︙ | |||
4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 |
if(vid!=0){
vfile_check_signature(vid, CKSIG_SETMTIME);
}
}
g.argc = 2;
info_cmd();
}
/*
** Print the current value of a setting identified by the pSetting
** pointer.
*/
| > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > > | | | > > > > > > > > > > > > > > > | > > > > > > | | 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 |
if(vid!=0){
vfile_check_signature(vid, CKSIG_SETMTIME);
}
}
g.argc = 2;
info_cmd();
}
/*
** Return true if pSetting has its default value assuming its
** current value is zVal.
*/
int setting_has_default_value(const Setting *pSetting, const char *zVal){
if( zVal==0 ) return 1;
if( pSetting->def==0 ) return 0;
if( pSetting->width==0 ){
return is_false(pSetting->def)==is_false(zVal);
}
if( fossil_strcmp(pSetting->def, zVal)==0 ) return 1;
if( is_false(zVal) && is_false(pSetting->def) ) return 1;
if( is_truth(zVal) && is_truth(pSetting->def) ) return 1;
return 0;
}
/*
** Print the current value of a setting identified by the pSetting
** pointer.
**
** Only show the value, not the setting name, if valueOnly is true.
**
** Show nothing if bIfChng is true and the setting is not currently set
** or is set to its default value.
*/
void print_setting(const Setting *pSetting, int valueOnly, int bIfChng){
Stmt q;
int versioned = 0;
if( pSetting->versionable && g.localOpen ){
/* Check to see if this is overridden by a versionable settings file */
Blob versionedPathname;
blob_zero(&versionedPathname);
blob_appendf(&versionedPathname, "%s.fossil-settings/%s",
g.zLocalRoot, pSetting->name);
if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){
versioned = 1;
}
blob_reset(&versionedPathname);
}
if( valueOnly && versioned ){
const char *zVal = db_get_versioned(pSetting->name, NULL, NULL);
if( !bIfChng || (zVal!=0 && fossil_strcmp(zVal, pSetting->def)!=0) ){
fossil_print("%s\n", db_get_versioned(pSetting->name, NULL, NULL));
}else{
versioned = 0;
}
return;
}
if( g.repositoryOpen ){
db_prepare(&q,
"SELECT '(local)', value FROM config WHERE name=%Q"
" UNION ALL "
"SELECT '(global)', value FROM global_config WHERE name=%Q",
pSetting->name, pSetting->name
);
}else{
db_prepare(&q,
"SELECT '(global)', value FROM global_config WHERE name=%Q",
pSetting->name
);
}
if( db_step(&q)==SQLITE_ROW ){
const char *zVal = db_column_text(&q,1);
if( bIfChng && setting_has_default_value(pSetting,zVal) ){
if( versioned ){
fossil_print("%-24s (versioned)\n", pSetting->name);
versioned = 0;
}
}else if( valueOnly ){
fossil_print("%s\n", db_column_text(&q, 1));
}else{
const char *zVal = (const char*)db_column_text(&q,1);
const char *zName = (const char*)db_column_text(&q,0);
if( zVal==0 ) zVal = "NULL";
if( strchr(zVal,'\n')==0 ){
fossil_print("%-24s %-11s %s\n", pSetting->name, zName, zVal);
}else{
fossil_print("%-24s %-11s\n", pSetting->name, zName);
while( zVal[0] ){
char *zNL = strchr(zVal, '\n');
if( zNL==0 ){
fossil_print(" %s\n", zVal);
break;
}else{
int n = (int)(zNL - zVal);
while( n>0 && fossil_isspace(zVal[n-1]) ){ n--; }
fossil_print(" %.*s\n", n, zVal);
zVal = zNL+1;
}
}
}
}
}else if( bIfChng ){
/* Display nothing */
versioned = 0;
}else if( valueOnly ){
fossil_print("\n");
}else{
fossil_print("%-24s\n", pSetting->name);
}
if( versioned ){
fossil_print(" (overridden by contents of file .fossil-settings/%s)\n",
pSetting->name);
}
db_finalize(&q);
}
|
| ︙ | ︙ | |||
4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 |
** negative for values which should not appear
** on the /setup_settings page. */
char versionable; /* Is this setting versionable? */
char forceTextArea; /* Force using a text area for display? */
char sensitive; /* True if this a security-sensitive setting */
const char *def; /* Default value */
};
#endif /* INTERFACE */
/*
| > | | | 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 |
** negative for values which should not appear
** on the /setup_settings page. */
char versionable; /* Is this setting versionable? */
char forceTextArea; /* Force using a text area for display? */
char sensitive; /* True if this a security-sensitive setting */
const char *def; /* Default value */
};
#endif /* INTERFACE */
/*
** SETTING: access-log boolean default=on
**
** When the access-log setting is enabled, all login attempts (successful
** and unsuccessful) on the web interface are recorded in the "access" table
** of the repository.
*/
/*
** SETTING: admin-log boolean default=on
**
** When the admin-log setting is enabled, configuration changes are recorded
** in the "admin_log" table of the repository.
*/
/*
** SETTING: allow-symlinks boolean default=off sensitive
**
|
| ︙ | ︙ | |||
4638 4639 4640 4641 4642 4643 4644 | /* ** SETTING: clearsign boolean default=off ** When enabled, fossil will attempt to sign all commits ** with gpg or ssh. When disabled, commits will be unsigned. */ /* ** SETTING: comment-format width=16 default=1 | | < < < | > > > > < | | < < < | 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 | /* ** SETTING: clearsign boolean default=off ** When enabled, fossil will attempt to sign all commits ** with gpg or ssh. When disabled, commits will be unsigned. */ /* ** SETTING: comment-format width=16 default=1 ** Set the algorithm for printing timeline comments to the console. ** ** Possible values are: ** 1 Use the original comment printing algorithm: ** * Leading and trialing whitespace is removed ** * Internal whitespace is converted into a single space (0x20) ** * Line breaks occurs at whitespace or hyphens if possible ** This is the recommended value and the default. ** ** Or a bitwise combination of the following flags: ** 2 Trim leading and trailing CR and LF characters. ** 4 Trim leading and trailing white space characters. ** 8 Attempt to break lines on word boundaries. ** 16 Break lines before the original comment embedded in other text. ** ** Note: To preserve line breaks and/or other whitespace within comment text, ** make this setting some integer value that omits the "1" bit. */ /* ** SETTING: crlf-glob width=40 versionable block-text ** The VALUE of this setting is a list of GLOB patterns matching files ** in which it is allowed to have CR, CR+LF or mixed line endings, ** suppressing Fossil's normal warning about this. Set it to "*" to ** disable CR+LF checking entirely. Example: *.md,*.txt |
| ︙ | ︙ | |||
4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 | ** SETTING: dotfiles boolean versionable default=off ** If enabled, include --dotfiles option for all compatible commands. */ /* ** SETTING: editor width=32 sensitive ** The value is an external command that will launch the ** text editor command used for check-in comments. */ /* ** SETTING: empty-dirs width=40 versionable block-text ** The value is a list of pathnames parsed according to the same rules as ** the *-glob settings. On update and checkout commands, if no directory ** exists with that name, an empty directory will be be created, even if ** it must create one or more parent directories. | > > > > > > > > | 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 |
** SETTING: dotfiles boolean versionable default=off
** If enabled, include --dotfiles option for all compatible commands.
*/
/*
** SETTING: editor width=32 sensitive
** The value is an external command that will launch the
** text editor command used for check-in comments.
**
** If this value is not set, then environment variables VISUAL and
** EDITOR are consulted, in that order. If neither of those are set,
** then a search is made for common text editors, including
** "notepad", "nano", "pico", "jove", "edit", "vi", "vim", and "ed".
**
** If this setting is false ("off", "no", "false", or "0") then no
** text editor is used.
*/
/*
** SETTING: empty-dirs width=40 versionable block-text
** The value is a list of pathnames parsed according to the same rules as
** the *-glob settings. On update and checkout commands, if no directory
** exists with that name, an empty directory will be be created, even if
** it must create one or more parent directories.
|
| ︙ | ︙ | |||
4757 4758 4759 4760 4761 4762 4763 | ** commits. If enabled on a server, whenever a client attempts ** to obtain a check-in lock during auto-sync, the server will ** send the "pragma avoid-delta-manifests" statement in its reply, ** which will cause the client to avoid generating a delta ** manifest. */ /* | | | > | 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 | ** commits. If enabled on a server, whenever a client attempts ** to obtain a check-in lock during auto-sync, the server will ** send the "pragma avoid-delta-manifests" statement in its reply, ** which will cause the client to avoid generating a delta ** manifest. */ /* ** SETTING: gdiff-command width=40 sensitive ** The value is an external command to run when performing a graphical ** diff. If undefined, a --tk diff is done if commands "tclsh" and "wish" ** are on PATH, or a --by diff is done if "tclsh" or "wish" are unavailable. */ /* ** SETTING: gmerge-command width=40 sensitive ** The value is a graphical merge conflict resolver command operating ** on four files. Examples: ** ** kdiff3 "%baseline" "%original" "%merge" -o "%output" |
| ︙ | ︙ | |||
4947 4948 4949 4950 4951 4952 4953 | ** 5) fossil all ui ** 6) fossil all server ** ** All repositories are searched (in lexicographical order) and the first ** repository with a non-zero "repolist-skin" value is used as the skin ** for the repository list page. If none of the repositories on the list ** have a non-zero "repolist-skin" setting then the repository list is | | > | 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 |
** 5) fossil all ui
** 6) fossil all server
**
** All repositories are searched (in lexicographical order) and the first
** repository with a non-zero "repolist-skin" value is used as the skin
** for the repository list page. If none of the repositories on the list
** have a non-zero "repolist-skin" setting then the repository list is
** displayed using unadorned HTML ("skinless"), with the page title taken
** from the FOSSIL_REPOLIST_TITLE environment variable.
**
** If repolist-skin has a value of 2, then the repository is omitted from
** the list in use cases 1 through 4, but not for 5 and 6.
*/
/*
** SETTING: self-pw-reset boolean default=off sensitive
** Allow users to request that an email containing a hyperlink
|
| ︙ | ︙ | |||
5152 5153 5154 5155 5156 5157 5158 5159 5160 | ** that applies to all repositories. The local values are stored in the ** "config" table of the repository and the global values are stored in the ** configuration database. If both a local and a global value exists for a ** setting, the local value takes precedence. This command normally operates ** on the local settings. Use the --global option to change global settings. ** ** Options: ** --global Set or unset the given property globally instead of ** setting or unsetting it for the open repository only | > > < > | 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 |
** that applies to all repositories. The local values are stored in the
** "config" table of the repository and the global values are stored in the
** configuration database. If both a local and a global value exists for a
** setting, the local value takes precedence. This command normally operates
** on the local settings. Use the --global option to change global settings.
**
** Options:
** --changed Only show settings if the value differs from the default
** --exact Only consider exact name matches
** --global Set or unset the given property globally instead of
** setting or unsetting it for the open repository only
** --value Only show the value of a given property (implies --exact)
**
** See also: [[configuration]]
*/
void setting_cmd(void){
int i;
int globalFlag = find_option("global","g",0)!=0;
int bIfChng = find_option("changed",0,0)!=0;
int exactFlag = find_option("exact",0,0)!=0;
int valueFlag = find_option("value",0,0)!=0;
/* Undocumented "--test-for-subsystem SUBSYS" option used to test
** the db_get_for_subsystem() interface: */
const char *zSubsys = find_option("test-for-subsystem",0,1);
int unsetFlag = g.argv[1][0]=='u';
int nSetting;
|
| ︙ | ︙ | |||
5186 5187 5188 5189 5190 5191 5192 |
if( unsetFlag && g.argc!=3 ){
usage("PROPERTY ?-global?");
}
if( valueFlag ){
if( g.argc!=3 ){
fossil_fatal("--value is only supported when qurying a given property");
}
| < | | 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 |
if( unsetFlag && g.argc!=3 ){
usage("PROPERTY ?-global?");
}
if( valueFlag ){
if( g.argc!=3 ){
fossil_fatal("--value is only supported when qurying a given property");
}
}
if( g.argc==2 ){
for(i=0; i<nSetting; i++){
print_setting(&aSetting[i], 0, bIfChng);
}
}else if( g.argc==3 || g.argc==4 ){
const char *zName = g.argv[2];
int n = (int)strlen(zName);
const Setting *pSetting = db_find_setting(zName, !exactFlag);
if( pSetting==0 ){
fossil_fatal("no such setting: %s", zName);
|
| ︙ | ︙ | |||
5246 5247 5248 5249 5250 5251 5252 |
fossil_print("%s (subsystem %s) ->", pSetting->name, zSubsys);
if( zValue ){
fossil_print(" [%s]", zValue);
fossil_free(zValue);
}
fossil_print("\n");
}else{
| | | 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 |
fossil_print("%s (subsystem %s) ->", pSetting->name, zSubsys);
if( zValue ){
fossil_print(" [%s]", zValue);
fossil_free(zValue);
}
fossil_print("\n");
}else{
print_setting(pSetting, valueFlag, bIfChng);
}
pSetting++;
}
}
}else{
usage("?PROPERTY? ?VALUE? ?-global?");
}
|
| ︙ | ︙ |
Changes to src/default.css.
| ︙ | ︙ | |||
748 749 750 751 752 753 754 755 756 757 758 759 760 761 |
border-bottom: 3px solid gold;
}
body.tkt div.content ol.tkt-changes > li:target > ol {
border-left: 1px solid gold;
}
body.cpage-ckout .file-change-line,
body.cpage-info .file-change-line,
body.cpage-vdiff .file-change-line {
margin-top: 16px;
margin-bottom: 16px;
margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
display: flex;
flex-direction: row;
justify-content: space-between;
| > | 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
border-bottom: 3px solid gold;
}
body.tkt div.content ol.tkt-changes > li:target > ol {
border-left: 1px solid gold;
}
body.cpage-ckout .file-change-line,
body.cpage-info .file-change-line,
body.cpage-vinfo .file-change-line,
body.cpage-vdiff .file-change-line {
margin-top: 16px;
margin-bottom: 16px;
margin-right: 1em /* keep it from nudging right up against the scrollbar-reveal zone */;
display: flex;
flex-direction: row;
justify-content: space-between;
|
| ︙ | ︙ |
Changes to src/descendants.c.
| ︙ | ︙ | |||
154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
" WHERE tagxref.rid=leaves.rid "
" AND tagxref.tagid=%d"
" AND tagxref.tagtype>0)",
TAG_CLOSED
);
}
}
/*
** Load the record ID rid and up to |N|-1 closest ancestors into
** the "ok" table. If N is zero, no limit. If ridBackTo is not zero
** then stop the search upon reaching the ancestor with rid==ridBackTo.
*/
void compute_ancestors(int rid, int N, int directOnly, int ridBackTo){
| > > > > > > > > > > > > > > > > > | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
" WHERE tagxref.rid=leaves.rid "
" AND tagxref.tagid=%d"
" AND tagxref.tagtype>0)",
TAG_CLOSED
);
}
}
/*
** If RID refers to a check-in, return the mtime of that check-in - the
** julian day number of when the check-in occurred.
*/
double mtime_of_rid(int rid, double mtime){
static Stmt q;
db_static_prepare(&q,"SELECT mtime FROM event WHERE objid=:rid");
db_bind_int(&q, ":rid", rid);
if( db_step(&q)==SQLITE_ROW ){
mtime = db_column_double(&q,0);
}
db_reset(&q);
return mtime;
}
/*
** Load the record ID rid and up to |N|-1 closest ancestors into
** the "ok" table. If N is zero, no limit. If ridBackTo is not zero
** then stop the search upon reaching the ancestor with rid==ridBackTo.
*/
void compute_ancestors(int rid, int N, int directOnly, int ridBackTo){
|
| ︙ | ︙ | |||
195 196 197 198 199 200 201 |
** (1) Primary parents
** (2) Merge parents
** (3) Cherrypick merge parents.
** (4) All ancestores of 1 and 2 but not of 3.
*/
double rLimitMtime = 0.0;
if( ridBackTo ){
| | < < | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
** (1) Primary parents
** (2) Merge parents
** (3) Cherrypick merge parents.
** (4) All ancestores of 1 and 2 but not of 3.
*/
double rLimitMtime = 0.0;
if( ridBackTo ){
rLimitMtime = mtime_of_rid(ridBackTo, 0.0);
}
db_multi_exec(
"WITH RECURSIVE\n"
" parent(pid,cid,isCP) AS (\n"
" SELECT plink.pid, plink.cid, 0 AS xisCP FROM plink\n"
" UNION ALL\n"
" SELECT parentid, childid, 1 FROM cherrypick WHERE NOT isExclude\n"
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
3173 3174 3175 3176 3177 3178 3179 |
nDel += c.aEdit[i+1];
nIns += c.aEdit[i+2];
}
g.diffCnt[1] += nIns;
g.diffCnt[2] += nDel;
if( nIns+nDel ){
g.diffCnt[0]++;
| > | > | 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 |
nDel += c.aEdit[i+1];
nIns += c.aEdit[i+2];
}
g.diffCnt[1] += nIns;
g.diffCnt[2] += nDel;
if( nIns+nDel ){
g.diffCnt[0]++;
if( !(pCfg->diffFlags & DIFF_BRIEF) ){
blob_appendf(pOut, "%10d %10d", nIns, nDel);
}
}
}else if( pCfg->diffFlags & (DIFF_RAW|DIFF_BY_TOKEN) ){
const int *R = c.aEdit;
unsigned int r;
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
blob_appendf(pOut, " copy %6d delete %6d insert %6d\n",
R[r], R[r+1], R[r+2]);
|
| ︙ | ︙ | |||
3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 |
pCfg->zBinGlob = diff_get_binary_glob();
zDiffBinary = find_option("diff-binary", 0, 1);
if( zDiffBinary ){
if( is_truth(zDiffBinary) ) diffFlags |= DIFF_INCBINARY;
}else if( db_get_boolean("diff-binary", 1) ){
diffFlags |= DIFF_INCBINARY;
}
}
}
if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
/* Deprecated, but retained for script compatibility. */
else if( find_option("new-file","N",0)!=0 ) diffFlags |= DIFF_VERBOSE;
pCfg->diffFlags = diffFlags;
| > > > > | 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 |
pCfg->zBinGlob = diff_get_binary_glob();
zDiffBinary = find_option("diff-binary", 0, 1);
if( zDiffBinary ){
if( is_truth(zDiffBinary) ) diffFlags |= DIFF_INCBINARY;
}else if( db_get_boolean("diff-binary", 1) ){
diffFlags |= DIFF_INCBINARY;
}
}else if( isGDiff) {
/* No external gdiff command found, using --by */
diffFlags |= DIFF_HTML|DIFF_WEBPAGE|DIFF_LINENO|DIFF_BROWSER
|DIFF_SIDEBYSIDE;
}
}
if( find_option("verbose","v",0)!=0 ) diffFlags |= DIFF_VERBOSE;
/* Deprecated, but retained for script compatibility. */
else if( find_option("new-file","N",0)!=0 ) diffFlags |= DIFF_VERBOSE;
pCfg->diffFlags = diffFlags;
|
| ︙ | ︙ |
Changes to src/diff.tcl.
| ︙ | ︙ | |||
88 89 90 91 92 93 94 |
upvar $iivar ii
if {$ii>=$N} {return -1}
set x [lindex $difftxt $ii]
incr ii
return $x
}
| > > > > > > > > > | > | | | | > > > > > > > > > > > > > > > > > > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
upvar $iivar ii
if {$ii>=$N} {return -1}
set x [lindex $difftxt $ii]
incr ii
return $x
}
proc reloadDiff {} {
global fossilcmd difftxt
unset -nocomplain difftxt
set idx [.txtA index @0,0]
readDiffs $fossilcmd 1
update
viewDiff $idx
}
proc readDiffs {fossilcmd redo} {
global difftxt debug
if {![info exists difftxt]} {
if {$debug} {
puts "# [list open $fossilcmd r]"
flush stdout
}
if {[catch {
set in [open $fossilcmd r]
fconfigure $in -encoding utf-8
set difftxt [split [read $in] \n]
close $in
} msg]} {
if {$redo} {
tk_messageBox -type ok -title Error -message "Unable to refresh:\n$msg"
return 0
} else {
puts $msg
exit 1
}
}
}
set N [llength $difftxt]
set ii 0
set nDiffs 0
set n1 0
set n2 0
array set widths {txt 3 ln 3 mkr 1}
if {$redo} {
foreach c [cols] {$c config -state normal}
.lnA delete 1.0 end
.txtA delete 1.0 end
.lnB delete 1.0 end
.txtB delete 1.0 end
.mkr delete 1.0 end
.wfiles.lb delete 0 end
}
set fromIndex [lsearch -glob $fossilcmd *-from]
set toIndex [lsearch -glob $fossilcmd *-to]
set branchIndex [lsearch -glob $fossilcmd *-branch]
set checkinIndex [lsearch -glob $fossilcmd *-checkin]
if {[lsearch -glob $fossilcmd *-label]>=0
|
| ︙ | ︙ | |||
457 458 459 460 461 462 463 |
}
::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
frame .spacer
| | | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 |
}
::ttk::scrollbar .sby -command {.txtA yview} -orient vertical
::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal
::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
frame .spacer
if {[readDiffs $fossilcmd 0] == 0} {
tk_messageBox -type ok -title $CFG(TITLE) -message "No changes"
exit
}
update idletasks
proc saveDiff {} {
set fn [tk_getSaveFile]
|
| ︙ | ︙ | |||
572 573 574 575 576 577 578 579 580 581 |
$w yview -pickplace $idx
$w tag add search search "$idx +$count chars"
$w tag config search -background {#fcc000}
}
set ::search $w
}
::ttk::button .bb.quit -text {Quit} -command exit
::ttk::button .bb.invert -text {Invert} -command invertDiff
::ttk::button .bb.save -text {Save As...} -command saveDiff
::ttk::button .bb.search -text {Search} -command searchOnOff
| > | | 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 |
$w yview -pickplace $idx
$w tag add search search "$idx +$count chars"
$w tag config search -background {#fcc000}
}
set ::search $w
}
::ttk::button .bb.quit -text {Quit} -command exit
::ttk::button .bb.reload -text {Reload} -command reloadDiff
::ttk::button .bb.invert -text {Invert} -command invertDiff
::ttk::button .bb.save -text {Save As...} -command saveDiff
::ttk::button .bb.search -text {Search} -command searchOnOff
pack .bb.quit .bb.reload .bb.invert -side left
if {$fossilcmd!=""} {pack .bb.save -side left}
pack .bb.files .bb.search -side left
grid rowconfigure . 1 -weight 1
grid columnconfigure . 1 -weight 1
grid columnconfigure . 4 -weight 1
grid .bb -row 0 -columnspan 6
eval grid [cols] -row 1 -sticky nsew
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
125 126 127 128 129 130 131 |
void diff_print_versions(const char *zFrom, const char *zTo, DiffConfig *pCfg){
if( (pCfg->diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|
DIFF_HTML|DIFF_WEBPAGE|DIFF_BROWSER|DIFF_JSON|DIFF_TCL))==0 ){
fossil_print("Fossil-Diff-From: %s\n",
zFrom[0]=='(' ? zFrom : mprintf("%S %s",
rid_to_uuid(symbolic_name_to_rid(zFrom, "ci")),
db_text("","SELECT datetime(%f)||' UTC'",
| | | | 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
void diff_print_versions(const char *zFrom, const char *zTo, DiffConfig *pCfg){
if( (pCfg->diffFlags & (DIFF_SIDEBYSIDE|DIFF_BRIEF|DIFF_NUMSTAT|
DIFF_HTML|DIFF_WEBPAGE|DIFF_BROWSER|DIFF_JSON|DIFF_TCL))==0 ){
fossil_print("Fossil-Diff-From: %s\n",
zFrom[0]=='(' ? zFrom : mprintf("%S %s",
rid_to_uuid(symbolic_name_to_rid(zFrom, "ci")),
db_text("","SELECT datetime(%f)||' UTC'",
symbolic_name_to_mtime(zFrom, 0, 0))));
fossil_print("Fossil-Diff-To: %s\n",
zTo[0]=='(' ? zTo : mprintf("%S %s",
rid_to_uuid(symbolic_name_to_rid(zTo, "ci")),
db_text("","SELECT datetime(%f)||' UTC'",
symbolic_name_to_mtime(zTo, 0, 1))));
fossil_print("%.66c\n", '-');
}
}
/*
** Print the "Index:" message that patches wants to see at the top of a diff.
*/
|
| ︙ | ︙ | |||
604 605 606 607 608 609 610 |
zName2 = NULL_DEVICE;
}else{
blob_read_from_file(&file2, zFile2, ExtFILE);
zName2 = zName;
}
/* Compute and output the differences */
| | > | > | 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
zName2 = NULL_DEVICE;
}else{
blob_read_from_file(&file2, zFile2, ExtFILE);
zName2 = zName;
}
/* Compute and output the differences */
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){
if( blob_compare(pFile1, &file2) ){
fossil_print("CHANGED %s\n", zName);
}
}else{
blob_zero(&out);
text_diff(pFile1, &file2, &out, pCfg);
if( blob_size(&out) ){
if( pCfg->diffFlags & DIFF_NUMSTAT ){
if( !(pCfg->diffFlags & DIFF_BRIEF) ){
blob_appendf(pOut, "%s %s\n", blob_str(&out), zName);
}
}else{
diff_print_filenames(zName, zName2, pCfg, pOut);
blob_appendf(pOut, "%s\n", blob_str(&out));
}
}
blob_reset(&out);
}
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 |
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
}else{
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
blob_append_escaped_arg(&cmd, zFile2, 1);
}
/* Run the external diff command */
| | > > > > > | 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 |
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
}else{
blob_append_escaped_arg(&cmd, blob_str(&nameFile1), 1);
blob_append_escaped_arg(&cmd, zFile2, 1);
}
/* Run the external diff command */
if( fossil_system(blob_str(&cmd)) ){
#if !defined(_WIN32)
/* On Windows, exit codes are unreliable. */
fossil_warning("External diff command failed: %b\n", &cmd);
#endif
}
/* Delete the temporary file and clean up memory used */
if( useTempfile ) file_delete(blob_str(&nameFile1));
blob_reset(&nameFile1);
blob_reset(&cmd);
}
}
|
| ︙ | ︙ | |||
710 711 712 713 714 715 716 |
*/
void diff_file_mem(
Blob *pFile1, /* In memory content to compare from */
Blob *pFile2, /* In memory content to compare to */
const char *zName, /* Display name of the file */
DiffConfig *pCfg /* Diff flags */
){
| | > > > | > | 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
*/
void diff_file_mem(
Blob *pFile1, /* In memory content to compare from */
Blob *pFile2, /* In memory content to compare to */
const char *zName, /* Display name of the file */
DiffConfig *pCfg /* Diff flags */
){
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){
return;
}
if( pCfg->zDiffCmd==0 ){
Blob out; /* Diff output text */
blob_zero(&out);
text_diff(pFile1, pFile2, &out, pCfg);
if( pCfg->diffFlags & DIFF_NUMSTAT ){
if( !(pCfg->diffFlags & DIFF_BRIEF) ){
fossil_print("%s %s\n", blob_str(&out), zName);
}
}else{
diff_print_filenames(zName, zName, pCfg, 0);
fossil_print("%s\n", blob_str(&out));
}
/* Release memory resources */
blob_reset(&out);
|
| ︙ | ︙ | |||
1007 1008 1009 1010 1011 1012 1013 |
if( pFrom ){
zName = pFrom->zName;
}else if( pTo ){
zName = pTo->zName;
}else{
zName = DIFF_NO_NAME;
}
| | > > | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 |
if( pFrom ){
zName = pFrom->zName;
}else if( pTo ){
zName = pTo->zName;
}else{
zName = DIFF_NO_NAME;
}
if( (pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT) ){
return;
}
diff_print_index(zName, pCfg, 0);
if( pFrom ){
rid = uuid_to_rid(pFrom->zUuid, 0);
content_get(rid, &f1);
}else{
blob_zero(&f1);
}
|
| ︙ | ︙ | |||
1095 1096 1097 1098 1099 1100 1101 |
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
/* No changes */
(void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
pFromFile = manifest_file_next(pFrom,0);
pToFile = manifest_file_next(pTo,0);
}else{
if( file_dir_match(pFileDir, pToFile->zName) ){
| | | 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 |
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
/* No changes */
(void)file_dir_match(pFileDir, pFromFile->zName); /* Record name usage */
pFromFile = manifest_file_next(pFrom,0);
pToFile = manifest_file_next(pTo,0);
}else{
if( file_dir_match(pFileDir, pToFile->zName) ){
if((pCfg->diffFlags & DIFF_BRIEF) && !(pCfg->diffFlags & DIFF_NUMSTAT)){
fossil_print("CHANGED %s\n", pFromFile->zName);
}else{
diff_manifest_entry(pFromFile, pToFile, pCfg);
}
}
pFromFile = manifest_file_next(pFrom,0);
pToFile = manifest_file_next(pTo,0);
|
| ︙ | ︙ | |||
1171 1172 1173 1174 1175 1176 1177 |
/*
** Return the name of the external diff command, or return NULL if
** no external diff command is defined.
*/
const char *diff_command_external(int guiDiff){
| | > | | | < > > > > > | < < > > > > > | | > > > | < < | | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 |
/*
** Return the name of the external diff command, or return NULL if
** no external diff command is defined.
*/
const char *diff_command_external(int guiDiff){
const char *zName;
zName = guiDiff ? "gdiff-command" : "diff-command";
return db_get(zName, 0);
}
/*
** Return true if it reasonable to run "diff -tk" for "gdiff".
**
** Details: Return true if all of the following are true:
**
** (1) The isGDiff flags is true
** (2) The "gdiff-command" setting is undefined
** (3) There is a "tclsh" on PATH
** (4) There is a "wish" on PATH
*/
int gdiff_using_tk(int isGdiff){
if( isGdiff
&& db_get("gdiff-command","")[0]==0
&& fossil_app_on_path("tclsh",0)
&& fossil_app_on_path("wish",0)
){
return 1;
}
return 0;
}
/*
** Show diff output in a Tcl/Tk window, in response to the --tk option
** to the diff command.
**
** If fossil has direct access to a Tcl interpreter (either loaded
|
| ︙ | ︙ | |||
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 |
int i;
Blob script;
const char *zTempFile = 0;
char *zCmd;
const char *zTclsh;
int bDebug = find_option("tkdebug",0,0)!=0;
int bDarkMode = find_option("dark",0,0)!=0;
blob_zero(&script);
/* Caution: When this routine is called from the merge-info command,
** the --tcl argument requires an argument. But merge-info does not
** use -i, so we can take -i as that argument. This routine needs to
** always have -i after --tcl.
** CAUTION!
** vvvvvvv */
| > | 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 |
int i;
Blob script;
const char *zTempFile = 0;
char *zCmd;
const char *zTclsh;
int bDebug = find_option("tkdebug",0,0)!=0;
int bDarkMode = find_option("dark",0,0)!=0;
(void)find_option("debug",0,0);
blob_zero(&script);
/* Caution: When this routine is called from the merge-info command,
** the --tcl argument requires an argument. But merge-info does not
** use -i, so we can take -i as that argument. This routine needs to
** always have -i after --tcl.
** CAUTION!
** vvvvvvv */
|
| ︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked- ** out. Or if the FILE arguments are omitted, show all unsaved changes | | > | 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | ** COMMAND: gdiff ** ** Usage: %fossil diff|gdiff ?OPTIONS? ?FILE1? ?FILE2 ...? ** ** Show the difference between the current version of each of the FILEs ** specified (as they exist on disk) and that same file as it was checked- ** out. Or if the FILE arguments are omitted, show all unsaved changes ** currently in the working check-out. The "gdiff" variant means to ** to use a GUI diff. ** ** The default output format is a "unified patch" (the same as the ** output of "diff -u" on most unix systems). Many alternative formats ** are available. A few of the more useful alternatives: ** ** --tk Pop up a Tcl/Tk-based GUI to show the diff ** --by Show a side-by-side diff in the default web browser |
| ︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | ** that directory as the baseline. ** -w|--ignore-all-space Ignore white space when comparing lines ** -i|--internal Use internal diff logic ** --invert Invert the diff ** --json Output formatted as JSON ** -n|--linenum Show line numbers ** -N|--new-file Alias for --verbose | | > > | 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 | ** that directory as the baseline. ** -w|--ignore-all-space Ignore white space when comparing lines ** -i|--internal Use internal diff logic ** --invert Invert the diff ** --json Output formatted as JSON ** -n|--linenum Show line numbers ** -N|--new-file Alias for --verbose ** --numstat Show the number of added and deleted lines per ** file, omitting the diff. When combined with ** --brief, show only the total row. ** -y|--side-by-side Side-by-side diff ** --strip-trailing-cr Strip trailing CR ** --tcl Tcl-formatted output used internally by --tk ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh") ** --tk Launch a Tcl/Tk GUI for display ** --to VERSION Select VERSION as target for the diff ** --undo Use the undo buffer as the baseline |
| ︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 | const char *zCheckin; /* Check-in version number */ const char *zBranch; /* Branch to diff */ int againstUndo = 0; /* Diff against files in the undo buffer */ FileDirList *pFileDir = 0; /* Restrict the diff to these files */ DiffConfig DCfg; /* Diff configuration object */ int bFromIsDir = 0; /* True if zFrom is a directory name */ | > | < > > > > > > > > > > | 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 |
const char *zCheckin; /* Check-in version number */
const char *zBranch; /* Branch to diff */
int againstUndo = 0; /* Diff against files in the undo buffer */
FileDirList *pFileDir = 0; /* Restrict the diff to these files */
DiffConfig DCfg; /* Diff configuration object */
int bFromIsDir = 0; /* True if zFrom is a directory name */
isGDiff = g.argv[1][0]=='g';
if( find_option("tk",0,0)!=0|| has_option("tclsh") ){
diff_tk("diff", 2);
return;
}
zFrom = find_option("from", "r", 1);
zTo = find_option("to", 0, 1);
zCheckin = find_option("checkin", "ci", 1);
zBranch = find_option("branch", 0, 1);
againstUndo = find_option("undo",0,0)!=0;
if( againstUndo && (zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){
fossil_fatal("cannot use --undo together with --from, --to, --checkin,"
" or --branch");
}
if( zBranch ){
if( zTo || zFrom || zCheckin ){
fossil_fatal("cannot use --from, --to, or --checkin with --branch");
}
zTo = zBranch;
zFrom = mprintf("root:%s", zBranch);
zBranch = 0;
}
if( zCheckin!=0 && (zFrom!=0 || zTo!=0) ){
fossil_fatal("cannot use --checkin together with --from or --to");
}
if( 0==zCheckin ){
if( zTo==0 || againstUndo ){
db_must_be_within_tree();
}else if( zFrom==0 ){
fossil_fatal("must use --from if --to is present");
}else{
db_find_and_open_repository(0, 0);
}
}else{
db_find_and_open_repository(0, 0);
}
if( gdiff_using_tk(isGDiff) ){
restore_option("--from", zFrom, 1);
restore_option("--to", zTo, 1);
restore_option("--checkin", zCheckin, 1);
restore_option("--branch", zBranch, 1);
if( againstUndo ) restore_option("--undo", 0, 0);
diff_tk("diff", 2);
return;
}
determine_exec_relative_option(1);
if( zFrom!=file_tail(zFrom)
&& file_isdir(zFrom, ExtFILE)==1
&& !db_exists("SELECT 1 FROM tag WHERE tagname='sym-%q'", zFrom)
){
bFromIsDir = 1;
|
| ︙ | ︙ | |||
1446 1447 1448 1449 1450 1451 1452 |
break;
}
pFileDir[i-2].nName = blob_size(&fname);
pFileDir[i-2].nUsed = 0;
blob_reset(&fname);
}
}
| > > > | | 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 |
break;
}
pFileDir[i-2].nName = blob_size(&fname);
pFileDir[i-2].nUsed = 0;
blob_reset(&fname);
}
}
if( DCfg.diffFlags & DIFF_NUMSTAT ){
fossil_print("%10s %10s\n", "INSERTED", "DELETED");
}
if( zCheckin!=0 ){
int ridTo = name_to_typed_rid(zCheckin, "ci");
zTo = zCheckin;
zFrom = db_text(0,
"SELECT uuid FROM blob, plink"
" WHERE plink.cid=%d AND plink.isprim AND plink.pid=blob.rid",
ridTo);
if( zFrom==0 ){
|
| ︙ | ︙ | |||
1486 1487 1488 1489 1490 1491 1492 |
}
fossil_free(pFileDir[i].zName);
}
fossil_free(pFileDir);
}
diff_end(&DCfg, 0);
if ( DCfg.diffFlags & DIFF_NUMSTAT ){
| | | | 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 |
}
fossil_free(pFileDir[i].zName);
}
fossil_free(pFileDir);
}
diff_end(&DCfg, 0);
if ( DCfg.diffFlags & DIFF_NUMSTAT ){
fossil_print("%10d %10d TOTAL over %d changed file%s\n",
g.diffCnt[1], g.diffCnt[2], g.diffCnt[0], g.diffCnt[0]!=1 ? "s": "");
}
}
/*
** WEBPAGE: vpatch
** URL: /vpatch?from=FROM&to=TO
**
|
| ︙ | ︙ |
Changes to src/dispatch.c.
| ︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ #define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret POST content */ /* NOTE: 0x0400 = CMDFLAG_SENSITIVE in mkindex.c! */ #define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */ #define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */ #define CMDFLAG_ALIAS 0x2000 /* Command aliases */ #define CMDFLAG_KEEPEMPTY 0x4000 /* Do not unset empty settings */ /**************************************************************************/ /* Values for the 2nd parameter to dispatch_name_search() */ #define CMDFLAG_ANY 0x0038 /* Match anything */ #define CMDFLAG_PREFIX 0x0200 /* Prefix match is ok */ #endif /* INTERFACE */ | > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #define CMDFLAG_BOOLEAN 0x0100 /* A boolean setting */ #define CMDFLAG_RAWCONTENT 0x0200 /* Do not interpret POST content */ /* NOTE: 0x0400 = CMDFLAG_SENSITIVE in mkindex.c! */ #define CMDFLAG_HIDDEN 0x0800 /* Elide from most listings */ #define CMDFLAG_LDAVG_EXEMPT 0x1000 /* Exempt from load_control() */ #define CMDFLAG_ALIAS 0x2000 /* Command aliases */ #define CMDFLAG_KEEPEMPTY 0x4000 /* Do not unset empty settings */ #define CMDFLAG_ABBREVSUBCMD 0x8000 /* Help text abbreviates subcommands */ /**************************************************************************/ /* Values for the 2nd parameter to dispatch_name_search() */ #define CMDFLAG_ANY 0x0038 /* Match anything */ #define CMDFLAG_PREFIX 0x0200 /* Prefix match is ok */ #endif /* INTERFACE */ |
| ︙ | ︙ | |||
520 521 522 523 524 525 526 |
blob_appendf(pHtml, "%s\n", azEnd[iLevel--]);
}
}
/*
** Format help text for TTY display.
*/
| | > > > > > > > > | 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 |
blob_appendf(pHtml, "%s\n", azEnd[iLevel--]);
}
}
/*
** Format help text for TTY display.
*/
static void help_to_text(const char *zHelp, Blob *pText, int bUsage){
int i, x;
char c;
if( zHelp[0]=='>' ){
if( !bUsage ){
blob_appendf(pText, "Usage:");
}else{
blob_append_char(pText, ' ');
}
zHelp++;
}
for(i=0; (c = zHelp[i])!=0; i++){
if( c=='%' && strncmp(zHelp+i,"%fossil",7)==0 ){
if( i>0 ) blob_append(pText, zHelp, i);
blob_append(pText, "fossil", 6);
zHelp += i+7;
i = -1;
continue;
|
| ︙ | ︙ | |||
601 602 603 604 605 606 607 |
}else if( rawOut ){
for(j=0; j<occHelp[aCommand[i].iHelp]; j++)
fossil_print("# %s\n", aCommand[bktHelp[aCommand[i].iHelp][j]].zName);
fossil_print("%s\n\n", aCommand[i].zHelp);
}else{
Blob txt;
blob_init(&txt, 0, 0);
| | | 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
}else if( rawOut ){
for(j=0; j<occHelp[aCommand[i].iHelp]; j++)
fossil_print("# %s\n", aCommand[bktHelp[aCommand[i].iHelp][j]].zName);
fossil_print("%s\n\n", aCommand[i].zHelp);
}else{
Blob txt;
blob_init(&txt, 0, 0);
help_to_text(aCommand[i].zHelp, &txt, 0);
for(j=0; j<occHelp[aCommand[i].iHelp]; j++){
fossil_print("# %s%s\n",
aCommand[bktHelp[aCommand[i].iHelp][j]].zName,
(aCommand[i].eCmdFlags & CMDFLAG_VERSIONABLE)!=0 ?
" (versionable)" : "");
}
fossil_print("%s\n\n", blob_str(&txt));
|
| ︙ | ︙ | |||
800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
n = dispatch_approx_match(g.argv[i], 20, az);
for(j=0; j<n; j++){
fossil_print(" %s\n", az[j]);
}
}
}
/*
** WEBPAGE: help
** URL: /help?name=CMD
**
** Show the built-in help text for CMD. CMD can be a command-line interface
** command or a page name from the web interface or a setting.
** Query parameters:
| > > > > > > > > > > > > > > > > > > > > > > | 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 |
n = dispatch_approx_match(g.argv[i], 20, az);
for(j=0; j<n; j++){
fossil_print(" %s\n", az[j]);
}
}
}
/*
** Returns 1 if the command or page name zName is known to be a
** command/page which is only available in certain builds/platforms,
** else returns 0.
*/
static int help_is_platform_command(const char *zName){
const char *aList[] = {
/* List of commands/pages which are known to only be available in
** certain builds/platforms. */
"winsrv",
"json", "/json",
NULL /* end-of-list sentinel */
};
int i = 0;
const char *z;
for( z = aList[0]; z ; z = aList[++i] ){
if( 0==fossil_strcmp(zName, z) ) return 1;
}
return 0;
}
/*
** WEBPAGE: help
** URL: /help?name=CMD
**
** Show the built-in help text for CMD. CMD can be a command-line interface
** command or a page name from the web interface or a setting.
** Query parameters:
|
| ︙ | ︙ | |||
827 828 829 830 831 832 833 |
if( zCmd==0 ) zCmd = P("name");
cgi_check_for_malice();
if( zCmd && *zCmd ){
int rc;
const CmdOrPage *pCmd = 0;
style_set_current_feature("tkt");
| | > > | < > > > > > > > | | | | > > > | > | | > | 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 |
if( zCmd==0 ) zCmd = P("name");
cgi_check_for_malice();
if( zCmd && *zCmd ){
int rc;
const CmdOrPage *pCmd = 0;
style_set_current_feature("tkt");
style_submenu_element("Topic-List", "%R/help");
if( search_restrict(SRCH_HELP)!=0 ){
style_submenu_element("Search","%R/search?y=h");
}
rc = dispatch_name_search(zCmd, CMDFLAG_ANY|CMDFLAG_PREFIX, &pCmd);
if( pCmd ){
style_header("Help: %s", pCmd->zName);
}else{
style_header("Help");
}
if( pCmd==0 ){
/* No <h1> line in this case */
}else if( *zCmd=='/' ){
/* Some of the webpages require query parameters in order to work.
** @ <h1>The "<a href='%R%s(zCmd)'>%s(zCmd)</a>" page:</h1> */
@ <h1>The "%h(pCmd->zName)" page:</h1>
}else if( rc==0 && (pCmd->eCmdFlags & CMDFLAG_SETTING)!=0 ){
@ <h1>The "%h(pCmd->zName)" setting:</h1>
}else{
@ <h1>The "%h(pCmd->zName)" command:</h1>
}
if( rc==1 || (rc==2 && zCmd[0]=='/') ){
if( zCmd && help_is_platform_command(zCmd) ){
@ Not available in this build: "%h(zCmd)"
}else{
@ Unknown topic: "%h(zCmd)"
}
}else if( rc==2 ){
@ Ambiguous prefix: "%h(zCmd)"
}else{
if( pCmd->zHelp[0]==0 ){
@ No help available for "%h(pCmd->zName)"
}else if( P("plaintext") ){
Blob txt;
blob_init(&txt, 0, 0);
help_to_text(pCmd->zHelp, &txt, 0);
@ <pre class="helpPage">
@ %h(blob_str(&txt))
@ </pre>
blob_reset(&txt);
}else if( P("raw") ){
@ <pre class="helpPage">
@ %h(pCmd->zHelp)
@ </pre>
}else{
@ <div class="helpPage">
help_to_html(pCmd->zHelp, cgi_output_blob());
@ </div>
}
}
}else{
int i;
const char *zWidth = "28ex";
unsigned char occHelp[FOSSIL_MX_CMDIDX] = {0}; /* Help str occurrences */
int bktHelp[FOSSIL_MX_CMDIDX][MX_HELP_DUP] = {{0}};/* Help str->commands */
style_header("Help");
search_screen(SRCH_HELP, 0x02);
@ <a name='commands'></a>
@ <h1>Available commands:</h1>
@ <div class="columns" style="column-width: %s(zWidth);">
@ <ul>
/* Fill in help string buckets */
for(i=0; i<MX_COMMAND; i++){
|
| ︙ | ︙ | |||
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 |
occHelp[aCommand[i].iHelp] = 0;
}
}
@ </dl>
blob_reset(&buf);
style_finish_page();
}
static void multi_column_list(const char **azWord, int nWord){
int i, j, len;
int mxLen = 0;
int nCol;
int nRow;
for(i=0; i<nWord; i++){
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 |
occHelp[aCommand[i].iHelp] = 0;
}
}
@ </dl>
blob_reset(&buf);
style_finish_page();
}
/*
** Analyze p and return one of three values:
**
** 0 p is the continuation of a prior subcommand.
**
** 1 p is text past the end of a prior subcommand.
**
** 2 p is the start of a new subcommand.
*/
static int is_subcommand(Blob *p, int bAbbrevSubcmd){
int i, sz;
const unsigned char *z = (const unsigned char*)blob_buffer(p);
sz = blob_size(p);
if( sz>6 ) sz = 6;
for(i=0; i<sz && fossil_isspace(z[i]); i++){}
if( i>=sz ) return 0;
if( bAbbrevSubcmd==0 ){
if( i>1 ) return 0;
return z[0]=='>' ? 2 : 1;
}else{
return (i==3 && fossil_isalpha(z[3])) ? 2 : 1;
}
}
/*
** Input z[] is help text for zTopic. If zTopic has sub-command zSub,
** then cut out all portions of the original help text that do not
** directly pertain to zSub and write the zSub-relevant parts into
** pOut.
**
** Return the number of lines of z[] written into pOut. A return of
** zero means no simplification occurred.
*/
static int simplify_to_subtopic(
const char *z, /* Full original help text */
Blob *pOut, /* Write simplified help text here */
const char *zTopic, /* TOPIC */
const char *zSubtopic, /* SUBTOPIC */
int bAbbrevSubcmd /* True if z[] contains abbreviated subcommands */
){
Blob in, line; //, subsection;
int n = 0;
char *zQTop = re_quote(zTopic);
char *zQSub = re_quote(zSubtopic);
char *zPattern;
ReCompiled *pRe = 0;
if( bAbbrevSubcmd ){
zPattern = mprintf(" ([a-z]+ ?\\| ?)*%s\\b", zQSub);
}else{
zPattern = mprintf("> ?fossil [-a-z]+ .*\\b%s\\b", zQSub);
}
fossil_free(zQTop);
fossil_free(zQSub);
re_compile(&pRe, zPattern, 0);
fossil_free(zPattern);
blob_init(&in, z, -1);
while( blob_line(&in, &line) ){
if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_size(&line)) ){
int atStart = 1;
blob_appendb(pOut, &line);
n++;
while( blob_line(&in, &line) ){
if( re_match(pRe,(unsigned char*)blob_buffer(&line),blob_size(&line)) ){
blob_appendb(pOut, &line);
n++;
atStart = 1;
}else{
int x = is_subcommand(&line,bAbbrevSubcmd);
if( x==2 ){
if( atStart ){
blob_appendb(pOut, &line);
n++;
}else{
break;
}
}else if( x==1 ){
break;
}else{
blob_appendb(pOut, &line);
n++;
atStart = 0;
}
}
}
}
}
blob_reset(&line);
re_free(pRe);
if( n ){
blob_trim(pOut);
blob_reset(&in);
}
return n;
}
/*
** Input p is a "Usage:" line or a subcommand line. Simplify this line
** for the --usage option and write it into pOut.
*/
static void simplify_usage_line(
Blob *p,
Blob *pOut,
int bAbbrevSubcmd,
const char *zCmd
){
const char *z = blob_buffer(p);
int sz = blob_size(p);
int i = 0;
if( sz>6 && z[0]=='U' ){
for(i=1; i<sz && !fossil_isspace(z[i]); i++){}
}else if( sz>0 && z[0]=='>' ){
i = 1;
}else if( sz>4 && bAbbrevSubcmd
&& memcmp(z," ",3)==0 && !fossil_isspace(z[3]) ){
int j;
for(j=3; j<sz-1 && (z[j]!=' ' || z[j+1]!=' '); j++){}
blob_appendf(pOut, "fossil %s %.*s\n", zCmd, j-3, &z[3]);
return;
}else{
while( i<sz && fossil_isspace(z[i]) ) i++;
if( i+2<sz && (z[i]=='o' || z[i]=='O') && z[i+1]=='r' ){
while( i<sz && !fossil_isspace(z[i]) ) i++;
}
}
while( i<sz && fossil_isspace(z[i]) ) i++;
blob_append(pOut, &z[i], sz-i);
}
/*
** Input z[] is help text for a command zTopic. Write into pOut all lines of
** z[] that show the command-line syntax for that command. Lines written
** to pOut are lines that begin with out of:
**
** Usage:
** or:
** > fossil TOPIC
**
** Return the number of lines written into pOut.
*/
static int simplify_to_usage(
const char *z, /* Full original help text */
Blob *pOut, /* Write simplified help text here */
const char *zTopic, /* The command for which z[] is full help text */
int bAbbrevSubcmd /* z[] uses abbreviated subcommands */
){
ReCompiled *pRe = 0;
Blob in, line;
int n = 0;
if( bAbbrevSubcmd ){
re_compile(&pRe, "^(Usage: | [a-z][-a-z|]+ .*)", 0);
}else{
re_compile(&pRe, "^(Usage: | *[Oo]r: +%fossi |> ?fossil )", 0);
}
blob_init(&in, z, -1);
while( blob_line(&in, &line) ){
if( re_match(pRe, (unsigned char*)blob_buffer(&line), blob_strlen(&line)) ){
simplify_usage_line(&line, pOut, bAbbrevSubcmd, zTopic);
n++;
}
}
re_free(pRe);
if( n ) blob_trim(pOut);
return n;
}
/*
** Input z[] is help text. Write into pOut all lines of z[] that show
** command-line options. Return the number of lines written.
*/
static int simplify_to_options(
const char *z, /* Full original help text */
Blob *pOut, /* Write simplified help text here */
int bAbbrevSubcmd, /* z[] uses abbreviated subcommands */
const char *zCmd /* Name of the command that z[] describes */
){
ReCompiled *pRe = 0;
Blob txt, line, subsection;
int n = 0;
int bSubsectionSeen = 0;
blob_init(&txt, z, -1);
blob_init(&subsection, 0, 0);
re_compile(&pRe, "^ +-.* ", 0);
while( blob_line(&txt, &line) ){
int len = blob_size(&line);
unsigned char *zLine = (unsigned char *)blob_buffer(&line);
if( re_match(pRe, zLine, len) ){
if( blob_size(&subsection) ){
simplify_usage_line(&subsection, pOut, bAbbrevSubcmd, zCmd);
blob_reset(&subsection);
}
blob_appendb(pOut, &line);
}else if( len>7 && !fossil_isspace(zLine[0]) && bSubsectionSeen
&& sqlite3_strlike("%options:%",blob_str(&line),0)==0 ){
subsection = line;
}else if( !bAbbrevSubcmd && len>9
&& (memcmp(zLine,"> fossil ",9)==0
|| memcmp(zLine,"> fossil",9)==0) ){
subsection = line;
bSubsectionSeen = 1;
}else if( bAbbrevSubcmd && len>5 && memcmp(zLine," ",3)==0
&& fossil_isalpha(zLine[3]) ){
subsection = line;
bSubsectionSeen = 1;
}else if( len>1 && !fossil_isspace(zLine[0]) && bSubsectionSeen ){
blob_reset(&subsection);
}
}
re_free(pRe);
blob_trim(pOut);
blob_reset(&subsection);
return n;
}
static void multi_column_list(const char **azWord, int nWord){
int i, j, len;
int mxLen = 0;
int nCol;
int nRow;
for(i=0; i<nWord; i++){
|
| ︙ | ︙ | |||
1123 1124 1125 1126 1127 1128 1129 | static const char zOptions[] = @ Command-line options common to all commands: @ @ --args FILENAME Read additional arguments and options from FILENAME @ --case-sensitive BOOL Set case sensitivity for file names @ --cgitrace Active CGI tracing @ --chdir PATH Change to PATH before performing any operations | < < | | > > > > > > < < < < > | > > > > | | | | | | | | > > > | > > | > > > | | < < | | 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 |
static const char zOptions[] =
@ Command-line options common to all commands:
@
@ --args FILENAME Read additional arguments and options from FILENAME
@ --case-sensitive BOOL Set case sensitivity for file names
@ --cgitrace Active CGI tracing
@ --chdir PATH Change to PATH before performing any operations
@ --errorlog FILENAME Log errors to FILENAME
@ --help Show help on the command rather than running it
@ --httptrace Trace outbound HTTP requests
@ --localtime Display times using the local timezone
@ --nocgi Do not act as CGI
@ --no-th-hook Do not run TH1 hooks
@ --quiet Reduce the amount of output
@ --sqlstats Show SQL usage statistics when done
@ --sqltrace Trace all SQL commands
@ --sshtrace Trace SSH activity
@ --ssl-identity NAME Set the SSL identity to NAME
@ --systemtrace Trace calls to system()
@ -U|--user USER Make the default user be USER
@ --utc Display times using UTC
@ --vfs NAME Cause SQLite to use the NAME VFS
;
/*
** COMMAND: help
**
** Usage: %fossil help [OPTIONS] [TOPIC] [SUBCOMMAND]
**
** Display information on how to use TOPIC, which may be a command, webpage, or
** setting. Webpage names begin with "/". If TOPIC is omitted, a list of
** topics is returned. If there is an extra argument after TOPIC, it is
** the name of a subcommand, in which case only the help text for that one
** subcommand is shown.
**
** The following options can be used when TOPIC is omitted:
**
** -a|--all List both common and auxiliary commands
** -e|--everything List all help on all topics
** -f|--full List full set of commands (including auxiliary
** and unsupported "test" commands), options,
** settings, and web pages
** -o|--options List command-line options common to all commands
** -s|--setting List setting names
** -t|--test List unsupported "test" commands
** -v|--verbose List both names and help text
** -x|--aux List only auxiliary commands
** -w|--www List all web pages
**
** These options can be used when TOPIC is present:
**
** -c|--commands Restrict TOPIC search to commands
** -h|--html Format output as HTML rather than plain text
** -o|--options Show command-line options for TOPIC
** --raw Output raw, unformatted help text
** -u|--usage Show a succinct usage summary, not full help text
**
** See also: [[usage]], [[options]], [[search]] with the -h option
*/
void help_cmd(void){
int rc;
int mask = CMDFLAG_ANY; /* Mask of help topic types */
int isPage = 0; /* True if TOPIC is a page */
int verboseFlag = 0; /* -v option */
int commandsFlag = 0; /* -c option */
const char *z; /* Original, untranslated help text */
const char *zCmdOrPage; /* "command" or "page" or "setting" */
const CmdOrPage *pCmd = 0; /* ptr to aCommand[] entry for TOPIC */
int useHtml = 0; /* -h option */
int bUsage; /* --usage */
int bRaw; /* --raw option */
int bOptions; /* --options */
const char *zTopic; /* TOPIC argument */
const char *zSubtopic = 0; /* SUBTOPIC argument */
Blob subtext1, subtext2, s3; /* Subsets of z[] containing subtopic/usage */
Blob txt; /* Text after rendering */
int bAbbrevSubcmd = 0; /* Help text uses abbreviated subcommands */
verboseFlag = find_option("verbose","v",0)!=0;
commandsFlag = find_option("commands","c",0)!=0;
useHtml = find_option("html","h",0)!=0;
bRaw = find_option("raw",0,0)!=0;
bOptions = find_option("options","o",0)!=0;
bUsage = find_option("usage","u",0)!=0;
if( find_option("all","a",0) ){
command_list(CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER, verboseFlag, useHtml);
return;
}
else if( find_option("www","w",0) ){
command_list(CMDFLAG_WEBPAGE, verboseFlag, useHtml);
return;
}
|
| ︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 |
fossil_print("\n%s", zOptions);
fossil_print("\nfossil settings:\n\n");
command_list(CMDFLAG_SETTING, verboseFlag, useHtml);
fossil_print("\nfossil web pages:\n\n");
command_list(CMDFLAG_WEBPAGE, verboseFlag, useHtml);
fossil_print("\nfossil test commands (unsupported):\n\n");
command_list(CMDFLAG_TEST, verboseFlag, useHtml);
| > | | > > > > > > | > > > | | > | > > > > | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > | > > | | | > > | 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 |
fossil_print("\n%s", zOptions);
fossil_print("\nfossil settings:\n\n");
command_list(CMDFLAG_SETTING, verboseFlag, useHtml);
fossil_print("\nfossil web pages:\n\n");
command_list(CMDFLAG_WEBPAGE, verboseFlag, useHtml);
fossil_print("\nfossil test commands (unsupported):\n\n");
command_list(CMDFLAG_TEST, verboseFlag, useHtml);
if ( !verboseFlag ) {
fossil_print("\n");
version_cmd();
}
return;
}
else if( find_option("everything","e",0) ){
display_all_help(CMDFLAG_1ST_TIER | CMDFLAG_2ND_TIER | CMDFLAG_WEBPAGE |
CMDFLAG_SETTING | CMDFLAG_TEST, useHtml, 0);
return;
}
verify_all_options();
if( g.argc<3 ){
if( bOptions ){
fossil_print("%s", zOptions);
return;
}
z = g.argv[0];
fossil_print(
"Usage: %s help TOPIC\n"
"Things to try:\n\n"
" %s help help\n"
" %s help -o\n"
" %s help -a\n"
" %s search -h TOPIC\n\n"
"Other common values for TOPIC:\n\n",
z, z, z, z, z);
command_list(CMDFLAG_1ST_TIER,verboseFlag,useHtml);
if( !verboseFlag ) version_cmd();
return;
}
zTopic = g.argv[2];
zSubtopic = g.argc>=4 ? g.argv[3] : 0;
isPage = ('/' == zTopic[0]) ? 1 : 0;
if( isPage ){
zCmdOrPage = "page";
}else if( commandsFlag ){
mask = CMDFLAG_COMMAND;
zCmdOrPage = "command";
}else{
zCmdOrPage = "command or setting";
}
rc = dispatch_name_search(g.argv[2], mask|CMDFLAG_PREFIX, &pCmd);
if( rc ){
int i, n;
const char *az[5];
if( rc==1 ){
if( help_is_platform_command(g.argv[2]) ){
fossil_print("Not available in this build: %s\n", g.argv[2]);
return;
}
fossil_print("unknown %s: %s\n", zCmdOrPage, g.argv[2]);
}else{
fossil_print("ambiguous %s prefix: %s\n",
zCmdOrPage, g.argv[2]);
}
fossil_print("Did you mean one of these TOPICs:\n");
n = dispatch_approx_match(g.argv[2], 5, az);
for(i=0; i<n; i++){
fossil_print(" * %s\n", az[i]);
}
fossil_print("Other commands to try:\n");
fossil_print(" fossil search -h PATTERN ;# search all help text\n");
fossil_print(" fossil help -a ;# show all commands\n");
fossil_print(" fossil help -w ;# show all web-pages\n");
fossil_print(" fossil help -s ;# show all settings\n");
fossil_print(" fossil help -o ;# show global options\n");
return;
}
bAbbrevSubcmd = (pCmd->eCmdFlags & CMDFLAG_ABBREVSUBCMD)!=0;
z = pCmd->zHelp;
if( z==0 ){
fossil_fatal("no help available for the %s %s",
pCmd->zName, zCmdOrPage);
}
blob_init(&subtext1, 0, 0);
blob_init(&subtext2, 0, 0);
blob_init(&s3, 0, 0);
if( zSubtopic!=0 ){
if( simplify_to_subtopic(z, &subtext1, zTopic, zSubtopic, bAbbrevSubcmd) ){
z = blob_str(&subtext1);
}else{
fossil_print("No subtopic \"%s\" for \"%s\".\n", zSubtopic, zTopic);
bUsage = 1;
zSubtopic = 0;
}
}
if( bUsage ){
if( simplify_to_usage(z, &subtext2, zTopic, bAbbrevSubcmd) ){
z = blob_str(&subtext2);
}else{
bUsage = 0;
}
}
if( bOptions ){
simplify_to_options(z, &s3, bAbbrevSubcmd, zTopic);
z = blob_str(&s3);
}
if( pCmd && pCmd->eCmdFlags & CMDFLAG_SETTING ){
const Setting *pSetting = db_find_setting(pCmd->zName, 0);
char *zDflt = 0;
if( pSetting!=0 && pSetting->def!=0 && *pSetting->def!=0 ){
zDflt = mprintf(" (default: %s)", pSetting->def);
}
fossil_print("Setting: \"%s\"%s%s\n\n",
pCmd->zName, zDflt!=0 ? zDflt : "",
(pCmd->eCmdFlags & CMDFLAG_VERSIONABLE)!=0 ? " (versionable)" : ""
);
fossil_free(zDflt);
}
blob_init(&txt, 0, 0);
if( bRaw ){
blob_append(&txt, z, -1);
}else if( useHtml ){
help_to_html(z, &txt);
}else{
help_to_text(z, &txt, bUsage || zSubtopic!=0);
}
if( blob_strlen(&txt)>0 ) fossil_print("%s\n", blob_str(&txt));
blob_reset(&txt);
blob_reset(&subtext1);
blob_reset(&subtext2);
}
/*
** Return a pointer to the setting information array.
**
** This routine provides access to the aSetting[] array which is created
** by the mkindex utility program and included with <page_index.h>.
|
| ︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 |
break;
case 3: /* helptext */
sqlite3_result_text(ctx, pPage->zHelp, -1, SQLITE_STATIC);
break;
case 4: { /* formatted */
Blob txt;
blob_init(&txt, 0, 0);
| | | 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 |
break;
case 3: /* helptext */
sqlite3_result_text(ctx, pPage->zHelp, -1, SQLITE_STATIC);
break;
case 4: { /* formatted */
Blob txt;
blob_init(&txt, 0, 0);
help_to_text(pPage->zHelp, &txt, 0);
sqlite3_result_text(ctx, blob_str(&txt), -1, fossil_free);
break;
}
case 5: { /* formatted */
Blob txt;
blob_init(&txt, 0, 0);
help_to_html(pPage->zHelp, &txt);
|
| ︙ | ︙ |
Changes to src/doc.c.
| ︙ | ︙ | |||
637 638 639 640 641 642 643 |
if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){
/* The text argument to data-title="" will have had any characters that
** are special to HTML encoded. We need to decode these before turning
** the text into a title, as the title text will be reencoded later */
char *zTitle = mprintf("%.*s", nValue, zValue);
int i;
for(i=0; fossil_isspace(zTitle[i]); i++){}
| | | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){
/* The text argument to data-title="" will have had any characters that
** are special to HTML encoded. We need to decode these before turning
** the text into a title, as the title text will be reencoded later */
char *zTitle = mprintf("%.*s", nValue, zValue);
int i;
for(i=0; fossil_isspace(zTitle[i]); i++){}
html_to_plaintext(zTitle+i, pTitle, 0);
fossil_free(zTitle);
seenTitle = 1;
if( seenClass ) return 1;
}
}
return seenClass;
}
|
| ︙ | ︙ | |||
805 806 807 808 809 810 811 812 813 814 815 816 817 818 |
}
blob_reset(&tail);
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
Blob tail = BLOB_INITIALIZER;
markdown_to_html(pBody, &title, &tail);
if( !isPopup ){
if( blob_size(&title)>0 ){
style_header("%s", blob_str(&title));
}else{
style_header("%s", zDefaultTitle);
}
}
convert_href_and_output(&tail);
if( !isPopup ){
| > | 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 |
}
blob_reset(&tail);
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){
Blob tail = BLOB_INITIALIZER;
markdown_to_html(pBody, &title, &tail);
if( !isPopup ){
if( blob_size(&title)>0 ){
markdown_dehtmlize_blob(&title);
style_header("%s", blob_str(&title));
}else{
style_header("%s", zDefaultTitle);
}
}
convert_href_and_output(&tail);
if( !isPopup ){
|
| ︙ | ︙ |
Changes to src/encode.c.
| ︙ | ︙ | |||
242 243 244 245 246 247 248 | *zOut = 0; return zRet; } /* ** Convert a single HEX digit to an integer */ | | | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
*zOut = 0;
return zRet;
}
/*
** Convert a single HEX digit to an integer
*/
int fossil_hexvalue(int c){
if( c>='a' && c<='f' ){
c += 10 - 'a';
}else if( c>='A' && c<='F' ){
c += 10 - 'A';
}else if( c>='0' && c<='9' ){
c -= '0';
}else{
|
| ︙ | ︙ | |||
270 271 272 273 274 275 276 |
if( !z ) return 0;
i = j = 0;
while( z[i] ){
switch( z[i] ){
case '%':
if( z[i+1] && z[i+2] ){
| | | | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
if( !z ) return 0;
i = j = 0;
while( z[i] ){
switch( z[i] ){
case '%':
if( z[i+1] && z[i+2] ){
z[j] = fossil_hexvalue(z[i+1]) << 4;
z[j] |= fossil_hexvalue(z[i+2]);
i += 2;
}
break;
case '+':
z[j] = ' ';
break;
default:
|
| ︙ | ︙ |
Changes to src/export.c.
| ︙ | ︙ | |||
478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
** --rename-trunk NAME Use NAME as name of exported trunk branch
** -R|--repository REPO Export the given REPOSITORY
**
** See also: import
*/
/*
** COMMAND: export*
**
** This command is deprecated. Use "fossil git export" instead.
*/
void export_cmd(void){
Stmt q, q2, q3;
Bag blobs, vers;
unsigned int unused_mark = 1;
| > > | 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
** --rename-trunk NAME Use NAME as name of exported trunk branch
** -R|--repository REPO Export the given REPOSITORY
**
** See also: import
*/
/*
** COMMAND: export*
**
** Usage: %fossil export --git [REPOSITORY]
**
** This command is deprecated. Use "fossil git export" instead.
*/
void export_cmd(void){
Stmt q, q2, q3;
Bag blobs, vers;
unsigned int unused_mark = 1;
|
| ︙ | ︙ | |||
1070 1071 1072 1073 1074 1075 1076 | ** ** Return zero on success and non-zero if the export should be stopped. */ static int gitmirror_send_checkin( FILE *xCmd, /* Write fast-import text on this pipe */ int rid, /* BLOB.RID for the check-in to export */ const char *zUuid, /* BLOB.UUID for the check-in to export */ | | < > > | | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 |
**
** Return zero on success and non-zero if the export should be stopped.
*/
static int gitmirror_send_checkin(
FILE *xCmd, /* Write fast-import text on this pipe */
int rid, /* BLOB.RID for the check-in to export */
const char *zUuid, /* BLOB.UUID for the check-in to export */
int *pnLimit /* Stop when the counter reaches zero */
){
Manifest *pMan; /* The check-in to be output */
int i; /* Loop counter */
int iParent; /* Which immediate ancestor is primary. -1 for none */
Stmt q; /* An SQL query */
char *zBranch; /* The branch of the check-in */
char *zMark; /* The Git-name of the check-in */
Blob sql; /* String of SQL for part of the query */
Blob comment; /* The comment text for the check-in */
int nErr = 0; /* Number of errors */
int bPhantomOk; /* True if phantom files should be ignored */
char buf[24];
char *zEmail; /* Contact info for Git committer field */
int fManifest; /* Should the manifest files be included? */
int fPManifest = 0; /* OR of the manifest files for all parents */
pMan = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pMan==0 ){
/* Must be a phantom. Return without doing anything, and in particular
** without creating a mark for this check-in. */
gitmirror_message(VERB_NORMAL, "missing check-in: %s\n", zUuid);
return 0;
}
/* Check to see if any parent logins have not yet been processed, and
** if so, create them */
for(i=0; i<pMan->nParent; i++){
char *zPMark = gitmirror_find_mark(pMan->azParent[i], 0, 0);
if( zPMark==0 ){
int prid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q",
pMan->azParent[i]);
int rc = gitmirror_send_checkin(xCmd, prid, pMan->azParent[i],
pnLimit);
if( rc || *pnLimit<=0 ){
manifest_destroy(pMan);
return 1;
}
}
fossil_free(zPMark);
}
|
| ︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
blob_appendf(&comment, "\n\nFossilOrigin-Name: %s", zUuid);
fprintf(xCmd, "data %d\n%s\n", blob_strlen(&comment), blob_str(&comment));
blob_reset(&comment);
iParent = -1; /* Which ancestor is the primary parent */
for(i=0; i<pMan->nParent; i++){
char *zOther = gitmirror_find_mark(pMan->azParent[i],0,0);
if( zOther==0 ) continue;
if( iParent<0 ){
iParent = i;
fprintf(xCmd, "from %s\n", zOther);
}else{
fprintf(xCmd, "merge %s\n", zOther);
}
fossil_free(zOther);
| > | 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 |
blob_appendf(&comment, "\n\nFossilOrigin-Name: %s", zUuid);
fprintf(xCmd, "data %d\n%s\n", blob_strlen(&comment), blob_str(&comment));
blob_reset(&comment);
iParent = -1; /* Which ancestor is the primary parent */
for(i=0; i<pMan->nParent; i++){
char *zOther = gitmirror_find_mark(pMan->azParent[i],0,0);
if( zOther==0 ) continue;
fPManifest |= db_get_manifest_setting(pMan->azParent[i]);
if( iParent<0 ){
iParent = i;
fprintf(xCmd, "from %s\n", zOther);
}else{
fprintf(xCmd, "merge %s\n", zOther);
}
fossil_free(zOther);
|
| ︙ | ︙ | |||
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
fossil_free(zFNQuoted);
}
db_finalize(&q);
manifest_destroy(pMan);
pMan = 0;
/* Include Fossil-generated auxiliary files in the check-in */
if( fManifest & MFESTFLG_RAW ){
Blob manifest;
content_get(rid, &manifest);
sterilize_manifest(&manifest, CFTYPE_MANIFEST);
fprintf(xCmd,"M 100644 inline manifest\ndata %d\n%s\n",
blob_strlen(&manifest), blob_str(&manifest));
blob_reset(&manifest);
}
if( fManifest & MFESTFLG_UUID ){
int n = (int)strlen(zUuid);
fprintf(xCmd,"M 100644 inline manifest.uuid\ndata %d\n%s\n\n", n+1, zUuid);
}
if( fManifest & MFESTFLG_TAGS ){
Blob tagslist;
blob_init(&tagslist, 0, 0);
get_checkin_taglist(rid, &tagslist);
fprintf(xCmd,"M 100644 inline manifest.tags\ndata %d\n%s\n",
blob_strlen(&tagslist), blob_str(&tagslist));
blob_reset(&tagslist);
}
/* The check-in is finished, so decrement the counter */
(*pnLimit)--;
return 0;
}
| > > > > > > > | 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 |
fossil_free(zFNQuoted);
}
db_finalize(&q);
manifest_destroy(pMan);
pMan = 0;
/* Include Fossil-generated auxiliary files in the check-in */
fManifest = db_get_manifest_setting(zUuid);
if( fManifest & MFESTFLG_RAW ){
Blob manifest;
content_get(rid, &manifest);
sterilize_manifest(&manifest, CFTYPE_MANIFEST);
fprintf(xCmd,"M 100644 inline manifest\ndata %d\n%s\n",
blob_strlen(&manifest), blob_str(&manifest));
blob_reset(&manifest);
}else if( fPManifest & MFESTFLG_RAW ){
fprintf(xCmd, "D manifest\n");
}
if( fManifest & MFESTFLG_UUID ){
int n = (int)strlen(zUuid);
fprintf(xCmd,"M 100644 inline manifest.uuid\ndata %d\n%s\n\n", n+1, zUuid);
}else if( fPManifest & MFESTFLG_UUID ){
fprintf(xCmd, "D manifest.uuid\n");
}
if( fManifest & MFESTFLG_TAGS ){
Blob tagslist;
blob_init(&tagslist, 0, 0);
get_checkin_taglist(rid, &tagslist);
fprintf(xCmd,"M 100644 inline manifest.tags\ndata %d\n%s\n",
blob_strlen(&tagslist), blob_str(&tagslist));
blob_reset(&tagslist);
}else if( fPManifest & MFESTFLG_TAGS ){
fprintf(xCmd, "D manifest.tags\n");
}
/* The check-in is finished, so decrement the counter */
(*pnLimit)--;
return 0;
}
|
| ︙ | ︙ | |||
1379 1380 1381 1382 1383 1384 1385 | const char *zAutoPush = 0; /* Value of the --autopush flag */ char *zMainBr = 0; /* Value of the --mainbranch flag */ char *zPushUrl; /* URL to sync the mirror to */ double rEnd; /* time of most recent export */ int rc; /* Result code */ int bForce; /* Do the export and sync even if no changes*/ int bNeedRepack = 0; /* True if we should run repack at the end */ | < | 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 |
const char *zAutoPush = 0; /* Value of the --autopush flag */
char *zMainBr = 0; /* Value of the --mainbranch flag */
char *zPushUrl; /* URL to sync the mirror to */
double rEnd; /* time of most recent export */
int rc; /* Result code */
int bForce; /* Do the export and sync even if no changes*/
int bNeedRepack = 0; /* True if we should run repack at the end */
int bIfExists; /* The --if-mirrored flag */
FILE *xCmd; /* Pipe to the "git fast-import" command */
FILE *pMarks; /* Git mark files */
Stmt q; /* Queries */
char zLine[200]; /* One line of a mark file */
zDebug = find_option("debug",0,1);
|
| ︙ | ︙ | |||
1517 1518 1519 1520 1521 1522 1523 |
" WHERE key='start'),0.0)")
){
gitmirror_message(VERB_NORMAL, "no changes\n");
db_commit_transaction();
return;
}
| < < < | 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 |
" WHERE key='start'),0.0)")
){
gitmirror_message(VERB_NORMAL, "no changes\n");
db_commit_transaction();
return;
}
/* Change to the MIRROR directory so that the Git commands will work */
rc = file_chdir(zMirror, 0);
if( rc ) fossil_fatal("cannot change the working directory to \"%s\"",
zMirror);
/* Start up the git fast-import command */
if( zDebug ){
|
| ︙ | ︙ | |||
1575 1576 1577 1578 1579 1580 1581 |
"SELECT objid, mtime, uuid FROM tomirror ORDER BY mtime"
);
while( nLimit && db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
double rMTime = db_column_double(&q, 1);
const char *zUuid = db_column_text(&q, 2);
if( rMTime>rEnd ) rEnd = rMTime;
| | | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 |
"SELECT objid, mtime, uuid FROM tomirror ORDER BY mtime"
);
while( nLimit && db_step(&q)==SQLITE_ROW ){
int rid = db_column_int(&q, 0);
double rMTime = db_column_double(&q, 1);
const char *zUuid = db_column_text(&q, 2);
if( rMTime>rEnd ) rEnd = rMTime;
rc = gitmirror_send_checkin(xCmd, rid, zUuid, &nLimit);
if( rc ) break;
gitmirror_message(VERB_NORMAL,"%d/%d \r", nTotal-nLimit, nTotal);
fflush(stdout);
}
db_finalize(&q);
fprintf(xCmd, "done\n");
if( zDebug ){
|
| ︙ | ︙ |
Changes to src/file.c.
| ︙ | ︙ | |||
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 |
/*
** COMMAND: test-which
**
** Usage: %fossil test-which ARGS...
**
** For each argument, search the PATH for the executable with the name
** and print its full pathname.
*/
void test_which_cmd(void){
int i;
for(i=2; i<g.argc; i++){
char *z = file_fullexename(g.argv[i]);
fossil_print("%z\n", z);
}
| > > > > > > > | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 |
/*
** COMMAND: test-which
**
** Usage: %fossil test-which ARGS...
**
** For each argument, search the PATH for the executable with the name
** and print its full pathname.
**
** See also the "which" command (without the "test-" prefix). The plain
** "which" command is more convenient to use since it provides the -a/-all
** option, and because it is shorter. The "fossil which" command without
** the "test-" prefix is recommended for day-to-day use. This command is
** retained because it tests the internal file_fullexename() function
** whereas plain "which" does not.
*/
void test_which_cmd(void){
int i;
for(i=2; i<g.argc; i++){
char *z = file_fullexename(g.argv[i]);
fossil_print("%z\n", z);
}
|
| ︙ | ︙ |
Changes to src/finfo.c.
| ︙ | ︙ | |||
496 497 498 499 500 501 502 |
" LEFT JOIN filename ON filename.fnid=clade.fnid\n"
"WHERE mlink.fnid=clade.fnid AND mlink.fid=clade.fid\n"
" AND event.objid=mlink.mid\n",
TAG_BRANCH
);
if( (zA = P("a"))!=0 ){
blob_append_sql(&sql, " AND event.mtime>=%.16g\n",
| | | | 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
" LEFT JOIN filename ON filename.fnid=clade.fnid\n"
"WHERE mlink.fnid=clade.fnid AND mlink.fid=clade.fid\n"
" AND event.objid=mlink.mid\n",
TAG_BRANCH
);
if( (zA = P("a"))!=0 ){
blob_append_sql(&sql, " AND event.mtime>=%.16g\n",
symbolic_name_to_mtime(zA,0,0));
url_add_parameter(&url, "a", zA);
}
if( (zB = P("b"))!=0 ){
blob_append_sql(&sql, " AND event.mtime<=%.16g\n",
symbolic_name_to_mtime(zB,0,1));
url_add_parameter(&url, "b", zB);
}
if( ridFrom ){
blob_append_sql(&sql,
" AND mlink.mid IN (SELECT rid FROM ancestor)\n"
"GROUP BY mlink.fid\n"
);
|
| ︙ | ︙ | |||
634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
}
db_reset(&qparent);
if( zBr==0 ) zBr = "trunk";
if( uBg ){
zBgClr = user_color(zUser);
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
}
gidx = graph_add_row(pGraph,
frid>0 ? (GraphRowId)frid*(mxfnid+1)+fnid : fpid+1000000000,
nParent, 0, aParent, zBr, zBgClr,
zUuid, 0);
if( strncmp(zDate, zPrevDate, 10) ){
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
| > > | 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 |
}
db_reset(&qparent);
if( zBr==0 ) zBr = "trunk";
if( uBg ){
zBgClr = user_color(zUser);
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
}else if( zBgClr ){
zBgClr = reasonable_bg_color(zBgClr,0);
}
gidx = graph_add_row(pGraph,
frid>0 ? (GraphRowId)frid*(mxfnid+1)+fnid : fpid+1000000000,
nParent, 0, aParent, zBr, zBgClr,
zUuid, 0);
if( strncmp(zDate, zPrevDate, 10) ){
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
|
| ︙ | ︙ |
Changes to src/fossil.page.pikchrshowasm.js.
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
if(PS._config.hasOwnProperty(k)){
PS.config[k] = PS._config[k];
}
});
delete PS._config;
}
| > > > | > > | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
if(PS._config.hasOwnProperty(k)){
PS.config[k] = PS._config[k];
}
});
delete PS._config;
}
/* Randomize the name of the worker script so that it is never cached.
** The Fossil /builtin method will automatically remove the "-v000000000"
** part of the filename, resolving it to just "pikchr-worker.js". */
PS.worker = new Worker('builtin/extsrc/pikchr-worker-v'+
(Math.floor(Math.random()*10000000000) + 1000000000)+
'.js');
PS.worker.onmessage = (ev)=>PS.runMsgHandlers(ev.data);
PS.addMsgHandler('stdout', console.log.bind(console));
PS.addMsgHandler('stderr', console.error.bind(console));
/** Handles status updates from the Module object. */
PS.addMsgHandler('module', function f(ev){
ev = ev.data;
|
| ︙ | ︙ | |||
170 171 172 173 174 175 176 |
PS.e.previewModeLabel.innerText =
PS.renderModeLabels[PS.renderModes[PS.renderModes.selectedIndex]];
/**
The 'pikchr-ready' event is fired (with no payload) when the
wasm module has finished loading. */
| | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
PS.e.previewModeLabel.innerText =
PS.renderModeLabels[PS.renderModes[PS.renderModes.selectedIndex]];
/**
The 'pikchr-ready' event is fired (with no payload) when the
wasm module has finished loading. */
PS.addMsgHandler('pikchr-ready', function(event){
PS.clearMsgHandlers('pikchr-ready');
F.page.onPikchrshowLoaded(event.data);
});
/**
Performs all app initialization which must wait until after the
worker module is loaded. This function removes itself when it's
called.
*/
F.page.onPikchrshowLoaded = function(pikchrVersion){
delete this.onPikchrshowLoaded;
// Unhide all elements which start out hidden
EAll('.initially-hidden').forEach((e)=>e.classList.remove('initially-hidden'));
const taInput = E('#input');
const btnClearIn = E('#btn-clear');
btnClearIn.addEventListener('click',function(){
taInput.value = '';
|
| ︙ | ︙ | |||
437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
link in the forum. */
const src = window.sessionStorage.getItem('pikchr-xfer');
if( src && (new URL(self.location.href).searchParams).has('fromSession') ){
taInput.value = src;
window.sessionStorage.removeItem('pikchr-xfer');
}
}
PS.e.btnRender.click();
/** Debounce handler for auto-rendering while typing. */
const debounceAutoRender = F.debounce(function f(){
if(!PS._isDirty) return;
const text = getCurrentText();
| > > > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
link in the forum. */
const src = window.sessionStorage.getItem('pikchr-xfer');
if( src && (new URL(self.location.href).searchParams).has('fromSession') ){
taInput.value = src;
window.sessionStorage.removeItem('pikchr-xfer');
}
}
D.append(E('fieldset.options > div'),
D.append(D.addClass(D.span(), 'labeled-input'),
'pikchr v. '+pikchrVersion));
PS.e.btnRender.click();
/** Debounce handler for auto-rendering while typing. */
const debounceAutoRender = F.debounce(function f(){
if(!PS._isDirty) return;
const text = getCurrentText();
|
| ︙ | ︙ | |||
522 523 524 525 526 527 528 |
delete ForceResizeKludge.$disabled;
ForceResizeKludge();
}/*onPikchrshowLoaded()*/;
/**
| | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
delete ForceResizeKludge.$disabled;
ForceResizeKludge();
}/*onPikchrshowLoaded()*/;
/**
Predefined example pikchr scripts. Each entry is an object:
{
name: required string,
code: optional code string. An entry with a falsy code is treated
like a separator in the resulting SELECT element (a
disabled OPTION).
}
|
| ︙ | ︙ |
Changes to src/fossil.page.wikiedit.js.
| ︙ | ︙ | |||
12 13 14 15 16 17 18 |
- Event 'wiki-page-loaded': passes on information when it
loads a wiki (whether from the network or its internal local-edit
cache), in the form of an "winfo" object:
{
name: string,
mimetype: mimetype string,
| | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
- Event 'wiki-page-loaded': passes on information when it
loads a wiki (whether from the network or its internal local-edit
cache), in the form of an "winfo" object:
{
name: string,
mimetype: mimetype string,
type: "normal" | "tag" | "checkin" | "branch" | "ticket" | "sandbox",
version: UUID string or null for a sandbox page or new page,
parent: parent UUID string or null if no parent,
isEmpty: true if page has no content (is "deleted").
content: string, optional in most contexts
}
The internal docs and code frequently use the term "winfo", and such
|
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
old = ndx[key];
const record = old || (ndx[key]={
name: winfo.name
});
record.mimetype = winfo.mimetype;
record.type = winfo.type;
record.parent = winfo.parent;
| | | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
old = ndx[key];
const record = old || (ndx[key]={
name: winfo.name
});
record.mimetype = winfo.mimetype;
record.type = winfo.type;
record.parent = winfo.parent;
record.version = winfo.version;
record.stashTime = new Date().getTime();
record.isEmpty = !!winfo.isEmpty;
record.attachments = winfo.attachments;
this.storeIndex();
if(arguments.length>1){
if(content) delete record.isEmpty;
F.storage.set(this.contentKey(key), content);
}
this._fireStashEvent();
return this;
},
/**
Returns the stashed content, if any, for the given winfo
object.
*/
stashedContent: function(winfo){
return F.storage.get(this.contentKey(this.indexKey(winfo)));
},
/** Returns true if we have stashed content for the given winfo
record or page name. */
hasStashedContent: function(winfo){
if('string'===typeof winfo) winfo = {name: winfo};
|
| ︙ | ︙ | |||
268 269 270 271 272 273 274 |
console.warn("Pruned oldest local file edit entry:",e);
}
if(n) this._fireStashEvent();
}
};
$stash.prune.defaultMaxCount = P.config.defaultMaxStashSize || 10;
P.$stash = $stash /* we have to expose this for the new-page case :/ */;
| | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
console.warn("Pruned oldest local file edit entry:",e);
}
if(n) this._fireStashEvent();
}
};
$stash.prune.defaultMaxCount = P.config.defaultMaxStashSize || 10;
P.$stash = $stash /* we have to expose this for the new-page case :/ */;
/**
Internal workaround to select the current preview mode
and fire a change event if the value actually changes
or if forceEvent is truthy.
*/
P.selectMimetype = function(modeValue, forceEvent){
const s = this.e.selectMimetype;
|
| ︙ | ︙ | |||
534 535 536 537 538 539 540 541 542 543 544 545 546 547 |
*/
addNewPage: function(name){
name = name.trim();
if(!this.validatePageName(name)) return false;
var wtype = 'normal';
if(0===name.indexOf('checkin/')) wtype = 'checkin';
else if(0===name.indexOf('branch/')) wtype = 'branch';
else if(0===name.indexOf('tag/')) wtype = 'tag';
/* ^^^ note that we're not validating that, e.g., checkin/XYZ
has a full artifact ID after "checkin/". */
const winfo = {
name: name, type: wtype, mimetype: 'text/x-markdown',
version: null, parent: null
};
| > | 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 |
*/
addNewPage: function(name){
name = name.trim();
if(!this.validatePageName(name)) return false;
var wtype = 'normal';
if(0===name.indexOf('checkin/')) wtype = 'checkin';
else if(0===name.indexOf('branch/')) wtype = 'branch';
else if(0===name.indexOf('ticket/')) wtype = 'ticket';
else if(0===name.indexOf('tag/')) wtype = 'tag';
/* ^^^ note that we're not validating that, e.g., checkin/XYZ
has a full artifact ID after "checkin/". */
const winfo = {
name: name, type: wtype, mimetype: 'text/x-markdown',
version: null, parent: null
};
|
| ︙ | ︙ | |||
571 572 573 574 575 576 577 |
D.attr(sel, 'size', 12);
D.option(D.disable(D.clearElement(sel)), undefined, "Loading...");
/** Set up filter checkboxes for the various types
of wiki pages... */
const fsFilter = D.addClass(D.fieldset("Page types"),"page-types-list"),
fsFilterBody = D.div(),
| | | 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
D.attr(sel, 'size', 12);
D.option(D.disable(D.clearElement(sel)), undefined, "Loading...");
/** Set up filter checkboxes for the various types
of wiki pages... */
const fsFilter = D.addClass(D.fieldset("Page types"),"page-types-list"),
fsFilterBody = D.div(),
filters = ['normal', 'branch/...', 'tag/...', 'checkin/...', 'ticket/...']
;
D.append(fsFilter, fsFilterBody);
D.addClass(fsFilterBody, 'flex-container', 'flex-column', 'stretch');
// Add filters by page type...
const self = this;
const filterByType = function(wtype, show){
|
| ︙ | ︙ | |||
1043 1044 1045 1046 1047 1048 1049 |
});
}else{
P.e.btnSave.addEventListener('click', ()=>doSave(), false);
P.e.btnSaveClose.addEventListener('click', ()=>doSave(true), false);
}
P.e.taEditor.addEventListener('change', ()=>P.notifyOfChange(), false);
| | | | 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
});
}else{
P.e.btnSave.addEventListener('click', ()=>doSave(), false);
P.e.btnSaveClose.addEventListener('click', ()=>doSave(true), false);
}
P.e.taEditor.addEventListener('change', ()=>P.notifyOfChange(), false);
P.selectMimetype(false, true);
P.e.selectMimetype.addEventListener(
'change',
function(e){
if(P.winfo && P.winfo.mimetype !== e.target.value){
P.winfo.mimetype = e.target.value;
P._isDirty = true;
P.stashContentChange(true);
}
},
false
);
const selectFontSize = E('select[name=editor_font_size]');
if(selectFontSize){
selectFontSize.addEventListener(
"change",function(e){
const ed = P.e.taEditor;
ed.className = ed.className.replace(
/\bfont-size-\d+/g, '' );
|
| ︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 |
).fetch('wikiajax/save',{
payload: fd,
responseType: 'json',
onload: callee.onload
});
return this;
};
| | | 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 |
).fetch('wikiajax/save',{
payload: fd,
responseType: 'json',
onload: callee.onload
});
return this;
};
/**
Updates P.winfo for certain state and stashes P.winfo, with the
current content fetched via P.wikiContent().
If passed truthy AND the stash already has stashed content for
the current page, only the stashed winfo record is updated, else
both the winfo and content are updated.
|
| ︙ | ︙ |
Changes to src/fuzz.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 | /* ** Type of fuzzing: */ #define FUZZ_WIKI 0 /* The Fossil-Wiki formatter */ #define FUZZ_MARKDOWN 1 /* The Markdown formatter */ #define FUZZ_ARTIFACT 2 /* Fuzz the artifact parser */ #define FUZZ_WIKI2 3 /* FOSSIL_WIKI and FOSSIL_MARKDOWN */ #endif /* The type of fuzzing to do */ static int eFuzzType = FUZZ_WIKI; /* The fuzzer invokes this routine once for each fuzzer input */ | > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /* ** Type of fuzzing: */ #define FUZZ_WIKI 0 /* The Fossil-Wiki formatter */ #define FUZZ_MARKDOWN 1 /* The Markdown formatter */ #define FUZZ_ARTIFACT 2 /* Fuzz the artifact parser */ #define FUZZ_WIKI2 3 /* FOSSIL_WIKI and FOSSIL_MARKDOWN */ #define FUZZ_COMFORMAT 4 /* comment_print() */ #endif /* The type of fuzzing to do */ static int eFuzzType = FUZZ_WIKI; /* The fuzzer invokes this routine once for each fuzzer input */ |
| ︙ | ︙ | |||
91 92 93 94 95 96 97 |
Blob title = BLOB_INITIALIZER;
wiki_convert(&in, &out, 0);
blob_reset(&out);
markdown_to_html(&in, &title, &out);
blob_reset(&title);
break;
}
| | > > > > > > > > > | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
Blob title = BLOB_INITIALIZER;
wiki_convert(&in, &out, 0);
blob_reset(&out);
markdown_to_html(&in, &title, &out);
blob_reset(&title);
break;
}
case FUZZ_ARTIFACT: {
fossil_fatal("FUZZ_ARTIFACT is not implemented.");
break;
}
case FUZZ_COMFORMAT: {
if( nByte>=3 && aData[1]!=0 && memchr(&aData[1], 0, nByte-1)!=0 ){
int flags = (int)aData[0];
comment_print((const char*)&aData[1],0,15,80,flags);
}
}
}
blob_reset(&in);
blob_reset(&out);
return 0;
}
/*
** Check fuzzer command-line options.
*/
static void fuzzer_options(void){
const char *zType;
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
db_multi_exec("PRAGMA query_only=1;");
zType = find_option("fuzztype",0,1);
if( zType==0 || fossil_strcmp(zType,"wiki")==0 ){
eFuzzType = FUZZ_WIKI;
}else if( fossil_strcmp(zType,"markdown")==0 ){
eFuzzType = FUZZ_MARKDOWN;
}else if( fossil_strcmp(zType,"wiki2")==0 ){
eFuzzType = FUZZ_WIKI2;
}else if( fossil_strcmp(zType,"comformat")==0 ){
eFuzzType = FUZZ_COMFORMAT;
}else{
fossil_fatal("unknown fuzz type: \"%s\"", zType);
}
}
/* Libfuzzer invokes this routine once prior to start-up to
** process command-line options.
|
| ︙ | ︙ | |||
137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
/*
** COMMAND: test-fuzz
**
** Usage: %fossil test-fuzz [-fuzztype TYPE] INPUTFILE...
**
** Run a fuzz test using INPUTFILE as the test data. TYPE can be one of:
**
** wiki Fuzz the Fossil-wiki translator
** markdown Fuzz the markdown translator
** artifact Fuzz the artifact parser
** wiki2 Fuzz the Fossil-wiki and markdown translator
*/
void fuzz_command(void){
Blob in;
| > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
/*
** COMMAND: test-fuzz
**
** Usage: %fossil test-fuzz [-fuzztype TYPE] INPUTFILE...
**
** Run a fuzz test using INPUTFILE as the test data. TYPE can be one of:
**
** comformat Fuzz the comment_print() routine
** wiki Fuzz the Fossil-wiki translator
** markdown Fuzz the markdown translator
** artifact Fuzz the artifact parser
** wiki2 Fuzz the Fossil-wiki and markdown translator
*/
void fuzz_command(void){
Blob in;
|
| ︙ | ︙ |
Changes to src/graph.c.
| ︙ | ︙ | |||
57 58 59 60 61 62 63 | ** the identifier is a combination of the BLOB.RID and the FILENAME.FNID ** values, and so it can become quite large for repos that have both many ** check-ins and many files. For this reason, we make the identifier ** a 64-bit integer, to dramatically reduce the risk of an overflow. */ typedef sqlite3_int64 GraphRowId; | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | ** the identifier is a combination of the BLOB.RID and the FILENAME.FNID ** values, and so it can become quite large for repos that have both many ** check-ins and many files. For this reason, we make the identifier ** a 64-bit integer, to dramatically reduce the risk of an overflow. */ typedef sqlite3_int64 GraphRowId; #define GR_MAX_RAIL 64 /* Max number of "rails" to display */ /* The graph appears vertically beside a timeline. Each row in the ** timeline corresponds to a row in the graph. GraphRow.idx is 0 for ** the top-most row and increases moving down. Hence (in the absence of ** time skew) parents have a larger index than their children. ** ** The nParent field is -1 for entires that do not participate in the graph |
| ︙ | ︙ | |||
82 83 84 85 86 87 88 | char *zBgClr; /* Background Color */ char zUuid[HNAME_MAX+1]; /* Check-in for file ID */ GraphRow *pNext; /* Next row down in the list of all rows */ GraphRow *pPrev; /* Previous row */ int idx; /* Row index. Top row is smallest. */ | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
char *zBgClr; /* Background Color */
char zUuid[HNAME_MAX+1]; /* Check-in for file ID */
GraphRow *pNext; /* Next row down in the list of all rows */
GraphRow *pPrev; /* Previous row */
int idx; /* Row index. Top row is smallest. */
int idxTop; /* Direct descendant highest up on the graph */
GraphRow *pChild; /* Child immediately above this node */
u8 isDup; /* True if this is duplicate of a prior entry */
u8 isLeaf; /* True if this is a leaf node */
u8 isStepParent; /* pChild is actually a step-child. The thick
** arrow up to the child is dashed, not solid */
u8 hasNormalOutMerge; /* Is parent of at laest 1 non-cherrypick merge */
u8 timeWarp; /* Child is earlier in time */
|
| ︙ | ︙ | |||
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
GraphRow *pLast; /* Last row in the list. Bottom row of graph. */
int nBranch; /* Number of distinct branches */
char **azBranch; /* Names of the branches */
int nRow; /* Number of rows */
int nHash; /* Number of slots in apHash[] */
u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different
** rail that the node */
u64 mergeRail; /* Rails used for merge lines */
GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */
};
#endif
| > | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
GraphRow *pLast; /* Last row in the list. Bottom row of graph. */
int nBranch; /* Number of distinct branches */
char **azBranch; /* Names of the branches */
int nRow; /* Number of rows */
int nHash; /* Number of slots in apHash[] */
u8 hasOffsetMergeRiser; /* Merge arrow from leaf goes up on a different
** rail that the node */
u8 bOverfull; /* Unable to allocate sufficient rails */
u64 mergeRail; /* Rails used for merge lines */
GraphRow **apHash; /* Hash table of GraphRow objects. Key: rid */
u8 aiRailMap[GR_MAX_RAIL]; /* Mapping of rails to actually columns */
};
#endif
|
| ︙ | ︙ | |||
334 335 336 337 338 339 340 |
if( dist<0 ) dist = -dist;
if( dist<iBestDist ){
iBestDist = dist;
iBest = i;
}
}
}
| | > > > > > > > | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
if( dist<0 ) dist = -dist;
if( dist<iBestDist ){
iBestDist = dist;
iBest = i;
}
}
}
if( iBestDist>1000 ){
p->bOverfull = 1;
iBest = GR_MAX_RAIL;
}
if( iBest>GR_MAX_RAIL ){
p->bOverfull = 1;
iBest = GR_MAX_RAIL;
}
if( iBest>p->mxRail ) p->mxRail = iBest;
if( bMergeRail ) p->mergeRail |= BIT(iBest);
return iBest;
}
/*
** Assign all children of node pBottom to the same rail as pBottom.
|
| ︙ | ︙ | |||
707 708 709 710 711 712 713 |
for(pRow=p->pLast; pRow; pRow=pRow->pPrev){
if( i==0 && pRow->zBranch!=zTrunk ) continue;
if( pRow->iRail>=0 ) continue;
if( pRow->isDup ) continue;
if( pRow->nParent<0 ) continue;
if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){
pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx+riserMargin,0,0);
| | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
for(pRow=p->pLast; pRow; pRow=pRow->pPrev){
if( i==0 && pRow->zBranch!=zTrunk ) continue;
if( pRow->iRail>=0 ) continue;
if( pRow->isDup ) continue;
if( pRow->nParent<0 ) continue;
if( pRow->nParent==0 || hashFind(p,pRow->aParent[0])==0 ){
pRow->iRail = findFreeRail(p, pRow->idxTop, pRow->idx+riserMargin,0,0);
/* if( p->mxRail>=GR_MAX_RAIL ) return; */
mask = BIT(pRow->iRail);
if( !omitDescenders ){
int n = RISER_MARGIN;
pRow->bDescender = pRow->nParent>0;
for(pLoop=pRow; pLoop && (n--)>0; pLoop=pLoop->pNext){
pLoop->railInUse |= mask;
}
|
| ︙ | ︙ | |||
742 743 744 745 746 747 748 |
continue;
}else{
assert( pRow->nParent>0 );
parentRid = pRow->aParent[0];
pParent = hashFind(p, parentRid);
if( pParent==0 ){
pRow->iRail = ++p->mxRail;
| | > > > | > > > > | > > > | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 |
continue;
}else{
assert( pRow->nParent>0 );
parentRid = pRow->aParent[0];
pParent = hashFind(p, parentRid);
if( pParent==0 ){
pRow->iRail = ++p->mxRail;
if( p->mxRail>=GR_MAX_RAIL ){
pRow->iRail = p->mxRail = GR_MAX_RAIL;
p->bOverfull = 1;
}
pRow->railInUse = BIT(pRow->iRail);
continue;
}
if( pParent->idx>pRow->idx ){
/* Common case: Child occurs after parent and is above the
** parent in the timeline */
pRow->iRail = findFreeRail(p, pRow->idxTop, pParent->idx,
pParent->iRail, 0);
/* if( p->mxRail>=GR_MAX_RAIL ) return; */
pParent->aiRiser[pRow->iRail] = pRow->idx;
}else{
/* Timewarp case: Child occurs earlier in time than parent and
** appears below the parent in the timeline. */
int iDownRail = ++p->mxRail;
if( iDownRail<1 ) iDownRail = ++p->mxRail;
if( p->mxRail>GR_MAX_RAIL ){
iDownRail = p->mxRail = GR_MAX_RAIL;
p->bOverfull = 1;
}
pRow->iRail = ++p->mxRail;
if( p->mxRail>=GR_MAX_RAIL ){
pRow->iRail = p->mxRail = GR_MAX_RAIL;
p->bOverfull = 1;
}
pRow->railInUse = BIT(pRow->iRail);
pParent->aiRiser[iDownRail] = pRow->idx;
mask = BIT(iDownRail);
for(pLoop=p->pFirst; pLoop; pLoop=pLoop->pNext){
pLoop->railInUse |= mask;
}
}
|
| ︙ | ︙ | |||
822 823 824 825 826 827 828 |
if( mergeRiserFrom[j]==parentRid ){
iMrail = j;
break;
}
}
if( iMrail==-1 ){
iMrail = findFreeRail(p, pRow->idx, p->pLast->idx, 0, 1);
| | | 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
if( mergeRiserFrom[j]==parentRid ){
iMrail = j;
break;
}
}
if( iMrail==-1 ){
iMrail = findFreeRail(p, pRow->idx, p->pLast->idx, 0, 1);
/*if( p->mxRail>=GR_MAX_RAIL ) return;*/
mergeRiserFrom[iMrail] = parentRid;
}
iReuseIdx = p->nRow+1;
iReuseRail = iMrail;
mask = BIT(iMrail);
if( i>=pRow->nNonCherrypick ){
pRow->mergeIn[iMrail] = 2;
|
| ︙ | ︙ | |||
854 855 856 857 858 859 860 |
}else{
pDesc->hasNormalOutMerge = 1;
pDesc->mergeUpto = pDesc->idx;
}
}else{
/* Create a new merge for an on-screen node */
createMergeRiser(p, pDesc, pRow, isCherrypick);
| | | | | | 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
}else{
pDesc->hasNormalOutMerge = 1;
pDesc->mergeUpto = pDesc->idx;
}
}else{
/* Create a new merge for an on-screen node */
createMergeRiser(p, pDesc, pRow, isCherrypick);
/* if( p->mxRail>=GR_MAX_RAIL ) return; */
if( iReuseIdx<0
&& pDesc->nMergeChild==1
&& (pDesc->iRail!=pDesc->mergeOut || pDesc->isLeaf)
){
iReuseIdx = pDesc->idx;
iReuseRail = pDesc->mergeOut;
}
}
}
}
}
/*
** Insert merge rails from primaries to duplicates.
*/
if( hasDup && p->mxRail<GR_MAX_RAIL ){
int dupRail;
int mxRail;
find_max_rail(p);
mxRail = p->mxRail;
dupRail = mxRail+1;
/* if( p->mxRail>=GR_MAX_RAIL ) return; */
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
if( !pRow->isDup ) continue;
pRow->iRail = dupRail;
pDesc = hashFind(p, pRow->rid);
assert( pDesc!=0 && pDesc!=pRow );
createMergeRiser(p, pDesc, pRow, 0);
if( pDesc->mergeOut>mxRail ) mxRail = pDesc->mergeOut;
}
if( dupRail<=mxRail ){
dupRail = mxRail+1;
for(pRow=p->pFirst; pRow; pRow=pRow->pNext){
if( pRow->isDup ) pRow->iRail = dupRail;
}
}
/* if( mxRail>=GR_MAX_RAIL ) return; */
}
/*
** Find the maximum rail number.
*/
find_max_rail(p);
|
| ︙ | ︙ |
Changes to src/hook.c.
| ︙ | ︙ | |||
196 197 198 199 200 201 202 | /* ** COMMAND: hook* ** ** Usage: %fossil hook COMMAND ... ** ** Commands include: ** | | | | | | | | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | /* ** COMMAND: hook* ** ** Usage: %fossil hook COMMAND ... ** ** Commands include: ** ** > fossil hook add --command COMMAND --type TYPE --sequence NUMBER ** ** Create a new hook. The --command and --type arguments are ** required. --sequence is optional. ** ** > fossil hook delete ID ... ** ** Delete one or more hooks by their IDs. ID can be "all" ** to delete all hooks. Caution: There is no "undo" for ** this operation. Deleted hooks are permanently lost. ** ** > fossil hook edit --command COMMAND --type TYPE --sequence NUMBER ID ... ** ** Make changes to one or more existing hooks. The ID argument ** is either a hook-id, or a list of hook-ids, or the keyword ** "all". For example, to disable hook number 2, use: ** ** fossil hook edit --type disabled 2 ** ** > fossil hook list ** ** Show all current hooks ** ** > fossil hook status ** ** Print the values of CONFIG table entries that are relevant to ** hook processing. Used for debugging. ** ** > fossil hook test [OPTIONS] ID ** ** Run the hook script given by ID for testing purposes. ** Options: ** ** --dry-run Print the script on stdout rather than run it ** --base-rcvid N Pretend that the hook-last-rcvid value is N ** --new-rcvid M Pretend that the last rcvid value is M |
| ︙ | ︙ |
Changes to src/http.c.
| ︙ | ︙ | |||
510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
blob_size(&hdr), blob_size(&payload));
}
transport_send(&g.url, &hdr);
transport_send(&g.url, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_flip(&g.url);
/*
** Read and interpret the server reply
*/
closeConnection = 1;
iLength = -1;
iHttpVersion = -1;
| > > > | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 |
blob_size(&hdr), blob_size(&payload));
}
transport_send(&g.url, &hdr);
transport_send(&g.url, &payload);
blob_reset(&hdr);
blob_reset(&payload);
transport_flip(&g.url);
if( mHttpFlags & HTTP_VERBOSE ){
fossil_print("IP-Address: %s\n", g.zIpAddr);
}
/*
** Read and interpret the server reply
*/
closeConnection = 1;
iLength = -1;
iHttpVersion = -1;
|
| ︙ | ︙ | |||
570 571 572 573 574 575 576 577 578 579 580 581 582 583 |
}else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){
closeConnection = 0;
}
}else if( ( rc==301 || rc==302 || rc==307 || rc==308 ) &&
fossil_strnicmp(zLine, "location:", 9)==0 ){
int i, j;
int wasHttps;
if ( --maxRedirect == 0){
fossil_warning("redirect limit exceeded");
goto write_err;
}
for(i=9; zLine[i] && zLine[i]==' '; i++){}
if( zLine[i]==0 ){
| > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
}else if( sqlite3_strlike("%keep-alive%", &zLine[11], 0)==0 ){
closeConnection = 0;
}
}else if( ( rc==301 || rc==302 || rc==307 || rc==308 ) &&
fossil_strnicmp(zLine, "location:", 9)==0 ){
int i, j;
int wasHttps;
int priorUrlFlags;
if ( --maxRedirect == 0){
fossil_warning("redirect limit exceeded");
goto write_err;
}
for(i=9; zLine[i] && zLine[i]==' '; i++){}
if( zLine[i]==0 ){
|
| ︙ | ︙ | |||
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
}
if( g.url.isFile || g.url.isSsh ){
fossil_warning("cannot redirect from %s to %s", g.url.canonical,
&zLine[i]);
goto write_err;
}
wasHttps = g.url.isHttps;
url_parse(&zLine[i], 0);
if( wasHttps && !g.url.isHttps ){
fossil_warning("cannot redirect from HTTPS to HTTP");
goto write_err;
}
if( g.url.isSsh || g.url.isFile ){
fossil_warning("cannot redirect to %s", &zLine[i]);
goto write_err;
}
transport_close(&g.url);
transport_global_shutdown(&g.url);
fSeenHttpAuth = 0;
if( g.zHttpAuth ) free(g.zHttpAuth);
g.zHttpAuth = get_httpauth();
| > > > | > | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
}
if( g.url.isFile || g.url.isSsh ){
fossil_warning("cannot redirect from %s to %s", g.url.canonical,
&zLine[i]);
goto write_err;
}
wasHttps = g.url.isHttps;
priorUrlFlags = g.url.flags;
url_parse(&zLine[i], 0);
if( wasHttps && !g.url.isHttps ){
fossil_warning("cannot redirect from HTTPS to HTTP");
goto write_err;
}
if( g.url.isSsh || g.url.isFile ){
fossil_warning("cannot redirect to %s", &zLine[i]);
goto write_err;
}
transport_close(&g.url);
transport_global_shutdown(&g.url);
fSeenHttpAuth = 0;
if( g.zHttpAuth ) free(g.zHttpAuth);
g.zHttpAuth = get_httpauth();
if( (rc==301 || rc==308) && (priorUrlFlags & URL_REMEMBER)!=0 ){
g.url.flags |= URL_REMEMBER;
url_remember();
}
return http_exchange(pSend, pReply, mHttpFlags,
maxRedirect, zAltMimetype);
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
isCompressed = 0;
}else if( fossil_strnicmp(&zLine[14],
"application/x-fossil-uncompressed", -1)==0 ){
|
| ︙ | ︙ | |||
791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
ssl_disable_cert_verification();
#endif
}
if( find_option("xfer",0,0)!=0 ){
mHttpFlags |= HTTP_USE_LOGIN;
mHttpFlags &= ~HTTP_GENERIC;
}
verify_all_options();
if( g.argc<3 || g.argc>5 ){
usage("URL ?PAYLOAD? ?OUTPUT?");
}
zInFile = g.argc>=4 ? g.argv[3] : 0;
if( g.argc==5 ){
if( zOutFile ){
| > | 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
ssl_disable_cert_verification();
#endif
}
if( find_option("xfer",0,0)!=0 ){
mHttpFlags |= HTTP_USE_LOGIN;
mHttpFlags &= ~HTTP_GENERIC;
}
if( find_option("ipv4",0,0) ) g.fIPv4 = 1;
verify_all_options();
if( g.argc<3 || g.argc>5 ){
usage("URL ?PAYLOAD? ?OUTPUT?");
}
zInFile = g.argc>=4 ? g.argv[3] : 0;
if( g.argc==5 ){
if( zOutFile ){
|
| ︙ | ︙ |
Changes to src/http_ssl.c.
| ︙ | ︙ | |||
449 450 451 452 453 454 455 |
const char *zRemoteHost;
ssl_global_init_client();
if( pUrlData->useProxy ){
int rc;
char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
BIO *sBio = BIO_new_connect(connStr);
| > > > > > > > | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
const char *zRemoteHost;
ssl_global_init_client();
if( pUrlData->useProxy ){
int rc;
char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
BIO *sBio = BIO_new_connect(connStr);
if( g.fIPv4 ){
#ifdef BIO_FAMILY_IPV4
BIO_set_conn_ip_family(sBio, BIO_FAMILY_IPV4);
#else
fossil_warning("The --ipv4 option is not supported in this build\n");
#endif
}
fossil_free(connStr);
if( BIO_do_connect(sBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
pUrlData->name, pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close_client();
return 1;
}
|
| ︙ | ︙ | |||
501 502 503 504 505 506 507 |
/* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
}
#endif
if( !pUrlData->useProxy ){
char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
BIO_set_conn_hostname(iBio, connStr);
| | > > > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
/* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
}
#endif
if( !pUrlData->useProxy ){
char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
BIO_set_conn_hostname(iBio, connStr);
fossil_free(connStr);
if( g.fIPv4 ){
#ifdef BIO_FAMILY_IPV4
BIO_set_conn_ip_family(iBio, BIO_FAMILY_IPV4);
#else
fossil_warning("The --ipv4 option is not supported in this build\n");
#endif
}
if( BIO_do_connect(iBio)<=0 ){
ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
pUrlData->name, pUrlData->port,
ERR_reason_error_string(ERR_get_error()));
ssl_close_client();
return 1;
}
|
| ︙ | ︙ | |||
908 909 910 911 912 913 914 |
static void trust_location_usable(const char *zPath, const char **pzStore){
if( *pzStore!=0 ) return;
if( file_isdir(zPath, ExtFILE)>0 ) *pzStore = zPath;
}
#endif /* FOSSIL_ENABLE_SSL */
/*
| | | | | | | | | | | | 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 |
static void trust_location_usable(const char *zPath, const char **pzStore){
if( *pzStore!=0 ) return;
if( file_isdir(zPath, ExtFILE)>0 ) *pzStore = zPath;
}
#endif /* FOSSIL_ENABLE_SSL */
/*
** COMMAND: tls-config* abbrv-subcom
** COMMAND: ssl-config abbrv-subcom
**
** Usage: %fossil ssl-config [SUBCOMMAND] [OPTIONS...] [ARGS...]
**
** This command is used to view or modify the TLS (Transport Layer
** Security) configuration for Fossil. TLS (formerly SSL) is the
** encryption technology used for secure HTTPS transport.
**
** Sub-commands:
**
** remove-exception DOMAINS Remove TLS cert exceptions for the domains
** listed. Or remove them all if the --all
** option is specified.
**
** scrub ?--force? Remove all SSL configuration data from the
** repository. Use --force to omit the
** confirmation.
**
** show ?-v? Show the TLS configuration. Add -v to see
** additional explanation
*/
void test_tlsconfig_info(void){
const char *zCmd;
size_t nCmd;
int nHit = 0;
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
255 256 257 258 259 260 261 |
}else{
z = blob_str(&vx);
}
fossil_print("fossil: %z\n", file_fullexename(g.nameOfExe));
fossil_print("version: %s", z);
blob_reset(&vx);
}
| | > > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
}else{
z = blob_str(&vx);
}
fossil_print("fossil: %z\n", file_fullexename(g.nameOfExe));
fossil_print("version: %s", z);
blob_reset(&vx);
}
}else if( g.repositoryOpen ){
int rid;
rid = name_to_rid(g.argv[2]);
if( rid==0 ){
fossil_fatal("no such object: %s", g.argv[2]);
}
show_common_info(rid, "hash:", 1, 1);
}else{
fossil_fatal("Could not find or open a Fossil repository");
}
}
/*
** Show the context graph (immediate parents and children) for
** check-in rid and rid2
*/
|
| ︙ | ︙ | |||
923 924 925 926 927 928 929 |
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = !db_exists("SELECT 1 FROM plink WHERE pid=%d", rid);
db_prepare(&q1,
| | | | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 |
zParent = db_text(0,
"SELECT uuid FROM plink, blob"
" WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim",
rid
);
isLeaf = !db_exists("SELECT 1 FROM plink WHERE pid=%d", rid);
db_prepare(&q1,
"SELECT uuid, datetime(mtime,toLocal(),'subsec'), user, comment,"
" datetime(omtime,toLocal(),'subsec'), mtime"
" FROM blob, event"
" WHERE blob.rid=%d"
" AND event.objid=%d",
rid, rid
);
zBrName = branch_of_rid(rid);
|
| ︙ | ︙ | |||
1364 1365 1366 1367 1368 1369 1370 |
}
if( !is_a_version(rid) ){
webpage_error("Artifact %s is not a check-in.", P(zParam));
return 0;
}
return manifest_get(rid, CFTYPE_MANIFEST, 0);
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 |
}
if( !is_a_version(rid) ){
webpage_error("Artifact %s is not a check-in.", P(zParam));
return 0;
}
return manifest_get(rid, CFTYPE_MANIFEST, 0);
}
/*
** WEBPAGE: vdiff
** URL: /vdiff?from=TAG&to=TAG
**
** Show the difference between two check-ins identified by the from= and
** to= query parameters.
|
| ︙ | ︙ | |||
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 |
fossil_print("%b\n", cgi_output_blob());
}
/*
** WEBPAGE: artifact
** WEBPAGE: file
** WEBPAGE: whatis
**
** Typical usage:
**
** /artifact/HASH
** /whatis/HASH
** /file/NAME
**
** Additional query parameters:
**
** ln - show line numbers
** ln=N - highlight line number N
** ln=M-N - highlight lines M through N inclusive
** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
** verbose - show more detail in the description
** download - redirect to the download (artifact page only)
** name=NAME - filename or hash as a query parameter
** filename=NAME - alternative spelling for "name="
** fn=NAME - alternative spelling for "name="
** ci=VERSION - The specific check-in to use with "name=" to
** identify the file.
** txt - Force display of unformatted source text
**
** The /artifact page show the complete content of a file
** identified by HASH. The /whatis page shows only a description
** of how the artifact is used. The /file page shows the most recent
** version of the file or directory called NAME, or a list of the
** top-level directory if NAME is omitted.
**
| > > > > > | 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 |
fossil_print("%b\n", cgi_output_blob());
}
/*
** WEBPAGE: artifact
** WEBPAGE: file
** WEBPAGE: whatis
** WEBPAGE: docfile
**
** Typical usage:
**
** /artifact/HASH
** /whatis/HASH
** /file/NAME
** /docfile/NAME
**
** Additional query parameters:
**
** ln - show line numbers
** ln=N - highlight line number N
** ln=M-N - highlight lines M through N inclusive
** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive)
** verbose - show more detail in the description
** brief - show just the document, not the metadata. The
** /docfile page is an alias for /file?brief
** download - redirect to the download (artifact page only)
** name=NAME - filename or hash as a query parameter
** filename=NAME - alternative spelling for "name="
** fn=NAME - alternative spelling for "name="
** ci=VERSION - The specific check-in to use with "name=" to
** identify the file.
** txt - Force display of unformatted source text
** hash - Output only the hash of the artifact
**
** The /artifact page show the complete content of a file
** identified by HASH. The /whatis page shows only a description
** of how the artifact is used. The /file page shows the most recent
** version of the file or directory called NAME, or a list of the
** top-level directory if NAME is omitted.
**
|
| ︙ | ︙ | |||
2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 |
** a default value of "tip" is used for ci= if ci= is omitted.
*/
void artifact_page(void){
int rid = 0;
Blob content;
const char *zMime;
Blob downloadName;
int renderAsWiki = 0;
int renderAsHtml = 0;
int renderAsSvg = 0;
int objType;
int asText;
const char *zUuid = 0;
u32 objdescFlags = OBJDESC_BASE;
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
int isFile = fossil_strcmp(g.zPath,"file")==0;
const char *zLn = P("ln");
const char *zName = P("name");
const char *zCI = P("ci");
HQuery url;
char *zCIUuid = 0;
int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
int isBranchCI = 0; /* ci= refers to a branch name */
char *zHeader = 0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
style_set_current_feature("artifact");
/* Capture and normalize the name= and ci= query parameters */
if( zName==0 ){
zName = P("filename");
if( zName==0 ){
zName = P("fn");
}
| > > > > > > > | 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 |
** a default value of "tip" is used for ci= if ci= is omitted.
*/
void artifact_page(void){
int rid = 0;
Blob content;
const char *zMime;
Blob downloadName;
Blob uuid;
int renderAsWiki = 0;
int renderAsHtml = 0;
int renderAsSvg = 0;
int objType;
int asText;
const char *zUuid = 0;
u32 objdescFlags = OBJDESC_BASE;
int descOnly = fossil_strcmp(g.zPath,"whatis")==0;
int hashOnly = P("hash")!=0;
int docOnly = P("brief")!=0;
int isFile = fossil_strcmp(g.zPath,"file")==0;
const char *zLn = P("ln");
const char *zName = P("name");
const char *zCI = P("ci");
HQuery url;
char *zCIUuid = 0;
int isSymbolicCI = 0; /* ci= exists and is a symbolic name, not a hash */
int isBranchCI = 0; /* ci= refers to a branch name */
char *zHeader = 0;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_check_for_malice();
style_set_current_feature("artifact");
if( fossil_strcmp(g.zPath, "docfile")==0 ){
isFile = 1;
docOnly = 1;
}
/* Capture and normalize the name= and ci= query parameters */
if( zName==0 ){
zName = P("filename");
if( zName==0 ){
zName = P("fn");
}
|
| ︙ | ︙ | |||
2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 |
if( descOnly || P("verbose")!=0 ){
url_add_parameter(&url, "verbose", "1");
objdescFlags |= OBJDESC_DETAIL;
}
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
etag_check(ETAG_HASH, zUuid);
asText = P("txt")!=0;
if( isFile ){
| > > > > > > > > > | | 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 |
if( descOnly || P("verbose")!=0 ){
url_add_parameter(&url, "verbose", "1");
objdescFlags |= OBJDESC_DETAIL;
}
zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
etag_check(ETAG_HASH, zUuid);
if( descOnly && hashOnly ){
blob_set(&uuid, zUuid);
cgi_set_content_type("text/plain");
cgi_set_content(&uuid);
return;
}
asText = P("txt")!=0;
if( isFile ){
if( docOnly ){
/* No header */
}else if( zCI==0 || fossil_strcmp(zCI,"tip")==0 ){
zCI = "tip";
@ <h2>File %z(href("%R/finfo?name=%T&m&ci=tip",zName))%h(zName)</a>
@ from the %z(href("%R/info/tip"))latest check-in</a></h2>
}else{
const char *zPath;
Blob path;
blob_zero(&path);
|
| ︙ | ︙ | |||
2872 2873 2874 2875 2876 2877 2878 |
}else if( isSymbolicCI ){
@ part of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
}else{
@ part of check-in %z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a></h2>
}
blob_reset(&path);
}
| < > > | | | | | > | 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 |
}else if( isSymbolicCI ){
@ part of check-in %z(href("%R/info/%!S",zCIUuid))%s(zCI)</a></h2>
}else{
@ part of check-in %z(href("%R/info/%!S",zCIUuid))%S(zCIUuid)</a></h2>
}
blob_reset(&path);
}
zMime = mimetype_from_name(zName);
if( !docOnly ){
style_submenu_element("Artifact", "%R/artifact/%S", zUuid);
style_submenu_element("Annotate", "%R/annotate?filename=%T&checkin=%T",
zName, zCI);
style_submenu_element("Blame", "%R/blame?filename=%T&checkin=%T",
zName, zCI);
style_submenu_element("Doc", "%R/doc/%T/%T", zCI, zName);
}
blob_init(&downloadName, zName, -1);
objType = OBJTYPE_CONTENT;
}else{
@ <h2>Artifact
style_copy_button(1, "hash-ar", 0, 2, "%s", zUuid);
if( g.perm.Setup ){
@ (%d(rid)):</h2>
|
| ︙ | ︙ | |||
2901 2902 2903 2904 2905 2906 2907 |
}
if( !descOnly && P("download")!=0 ){
cgi_redirectf("%R/raw/%s?at=%T",
db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
file_tail(blob_str(&downloadName)));
/*NOTREACHED*/
}
| | | 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 |
}
if( !descOnly && P("download")!=0 ){
cgi_redirectf("%R/raw/%s?at=%T",
db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
file_tail(blob_str(&downloadName)));
/*NOTREACHED*/
}
if( g.perm.Admin && !docOnly ){
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
style_submenu_element("Unshun", "%R/shun?accept=%s&sub=1#accshun", zUuid);
}else{
style_submenu_element("Shun", "%R/shun?shun=%s#addshun",zUuid);
}
}
|
| ︙ | ︙ | |||
2946 2947 2948 2949 2950 2951 2952 |
const char *zUser = db_column_text(&q,0);
const char *zDate = db_column_text(&q,1);
const char *zIp = db_column_text(&q,2);
@ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p>
}
db_finalize(&q);
}
| > | | | > > | > > | > > | | | > | > | > | 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 |
const char *zUser = db_column_text(&q,0);
const char *zDate = db_column_text(&q,1);
const char *zIp = db_column_text(&q,2);
@ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p>
}
db_finalize(&q);
}
if( !docOnly ){
style_submenu_element("Download", "%R/raw/%s?at=%T",zUuid,file_tail(zName));
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
style_submenu_element("Check-ins Using", "%R/timeline?uf=%s", zUuid);
}
}
if( zMime ){
if( fossil_strcmp(zMime, "text/html")==0 ){
if( asText ){
style_submenu_element("Html", "%s", url_render(&url, "txt", 0, 0, 0));
}else{
renderAsHtml = 1;
if( !docOnly ){
style_submenu_element("Text", "%s", url_render(&url, "txt","1",0,0));
}
}
}else if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0
|| fossil_strcmp(zMime, "text/x-markdown")==0
|| fossil_strcmp(zMime, "text/x-pikchr")==0 ){
if( asText ){
style_submenu_element(zMime[7]=='p' ? "Pikchr" : "Wiki",
"%s", url_render(&url, "txt", 0, 0, 0));
}else{
renderAsWiki = 1;
if( !docOnly ){
style_submenu_element("Text", "%s", url_render(&url, "txt","1",0,0));
}
}
}else if( fossil_strcmp(zMime, "image/svg+xml")==0 ){
if( asText ){
style_submenu_element("Svg", "%s", url_render(&url, "txt", 0, 0, 0));
}else{
renderAsSvg = 1;
if( !docOnly ){
style_submenu_element("Text", "%s", url_render(&url, "txt","1",0,0));
}
}
}
if( !docOnly && fileedit_is_editable(zName) ){
style_submenu_element("Edit",
"%R/fileedit?filename=%T&checkin=%!S",
zName, zCI);
}
}
if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){
style_submenu_element("Parsed", "%R/info/%s", zUuid);
}
if( descOnly ){
style_submenu_element("Content", "%R/artifact/%s", zUuid);
}else{
if( !docOnly || !isFile ){
@ <hr>
}
content_get(rid, &content);
if( renderAsWiki ){
safe_html_context(DOCSRC_FILE);
wiki_render_by_mimetype(&content, zMime);
document_emit_js();
}else if( renderAsHtml ){
@ <iframe src="%R/raw/%s(zUuid)"
|
| ︙ | ︙ | |||
3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewColorFlag = P("newclr") ? " checked" : "";
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zCloseFlag = P("close") ? " checked" : "";
zHideFlag = P("hide") ? " checked" : "";
if( P("apply") && cgi_csrf_safe(2) ){
Blob ctrl;
char *zNow;
blob_zero(&ctrl);
| > | 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 |
rid, TAG_BGCOLOR)==2;
fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor;
zNewColorFlag = P("newclr") ? " checked" : "";
zNewTagFlag = P("newtag") ? " checked" : "";
zNewTag = PDT("tagname","");
zNewBrFlag = P("newbr") ? " checked" : "";
zNewBranch = PDT("brname","");
zBranchName = branch_of_rid(rid);
zCloseFlag = P("close") ? " checked" : "";
zHideFlag = P("hide") ? " checked" : "";
if( P("apply") && cgi_csrf_safe(2) ){
Blob ctrl;
char *zNow;
blob_zero(&ctrl);
|
| ︙ | ︙ | |||
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 |
blob_zero(&comment);
blob_append(&comment, zNewComment, -1);
zUuid[10] = 0;
style_header("Edit Check-in [%s]", zUuid);
if( P("preview") ){
Blob suffix;
int nTag = 0;
@ <b>Preview:</b>
@ <blockquote>
@ <table border=0>
if( zNewColorFlag[0] && zNewColor && zNewColor[0] ){
| > > > > > > | > > | | 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 |
blob_zero(&comment);
blob_append(&comment, zNewComment, -1);
zUuid[10] = 0;
style_header("Edit Check-in [%s]", zUuid);
if( P("preview") ){
Blob suffix;
int nTag = 0;
const char *zDplyBr; /* Branch name used to determine BG color */
if( zNewBrFlag[0] && zNewBranch[0] ){
zDplyBr = zNewBranch;
}else{
zDplyBr = zBranchName;
}
@ <b>Preview:</b>
@ <blockquote>
@ <table border=0>
if( zNewColorFlag[0] && zNewColor && zNewColor[0] ){
@ <tr><td style="background-color:%h(reasonable_bg_color(zNewColor,0));">
}else if( zColor[0] ){
@ <tr><td style="background-color:%h(reasonable_bg_color(zColor,0));">
}else if( zDplyBr && fossil_strcmp(zDplyBr,"trunk")!=0 ){
@ <tr><td style="background-color:%h(hash_color(zDplyBr));">
}else{
@ <tr><td>
}
@ %!W(blob_str(&comment))
blob_zero(&suffix);
blob_appendf(&suffix, "(user: %h", zNewUser);
db_prepare(&q, "SELECT substr(tagname,5) FROM tagxref, tag"
|
| ︙ | ︙ | |||
3796 3797 3798 3799 3800 3801 3802 | @ </td></tr> @ <tr><th align="right" valign="top">Tags:</th> @ <td valign="top"> @ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag)> @ Add the following new tag name to this check-in:</label> @ <input size="15" name="tagname" id="tagname" value="%h(zNewTag)"> | < < < | 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 |
@ </td></tr>
@ <tr><th align="right" valign="top">Tags:</th>
@ <td valign="top">
@ <label><input type="checkbox" id="newtag" name="newtag"%s(zNewTagFlag)>
@ Add the following new tag name to this check-in:</label>
@ <input size="15" name="tagname" id="tagname" value="%h(zNewTag)">
db_prepare(&q,
"SELECT tag.tagid, tagname, tagxref.value FROM tagxref, tag"
" WHERE tagxref.rid=%d AND tagtype>0 AND tagxref.tagid=tag.tagid"
" ORDER BY CASE WHEN tagname GLOB 'sym-*' THEN substr(tagname,5)"
" ELSE tagname END /*sort*/",
rid
);
|
| ︙ | ︙ | |||
3939 3940 3941 3942 3943 3944 3945 | ** COMMAND: amend ** ** Usage: %fossil amend HASH OPTION ?OPTION ...? ** ** Amend the tags on check-in HASH to change how it displays in the timeline. ** ** Options: | | < < < < | > | < | > | > > | | > | > | | | 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 | ** COMMAND: amend ** ** Usage: %fossil amend HASH OPTION ?OPTION ...? ** ** Amend the tags on check-in HASH to change how it displays in the timeline. ** ** Options: ** --author USER Make USER the author for check-in ** --bgcolor COLOR Apply COLOR to this check-in ** --branch NAME Rename branch of check-in to NAME ** --branchcolor COLOR Apply and propagate COLOR to the branch ** --cancel TAG Cancel TAG from this check-in ** --close Mark this "leaf" as closed ** --date DATETIME Make DATETIME the check-in time ** --date-override DATETIME Set the change time on the control artifact ** -e|--edit-comment Launch editor to revise comment ** --hide Hide branch starting from this check-in ** -m|--comment COMMENT Make COMMENT the check-in comment ** -M|--message-file FILE Read the amended comment from FILE ** -n|--dry-run Print control artifact, but make no changes ** --no-verify-comment Do not validate the check-in comment ** --tag TAG Add new TAG to this check-in ** --user-override USER Set the user name on the control artifact ** ** DATETIME may be "now" or "YYYY-MM-DDTHH:MM:SS.SSS". If in ** year-month-day form, it may be truncated, the "T" may be replaced by ** a space, and it may also name a timezone offset from UTC as "-HH:MM" ** (westward) or "+HH:MM" (eastward). Either no timezone suffix or "Z" ** means UTC. */ |
| ︙ | ︙ | |||
3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 |
int fHide; /* True if branch should be hidden */
int fPropagateColor; /* True if color propagates before amend */
int fNewPropagateColor = 0; /* True if color propagates after amend */
int fHasHidden = 0; /* True if hidden tag already set */
int fHasClosed = 0; /* True if closed tag already set */
int fEditComment; /* True if editor to be used for comment */
int fDryRun; /* Print control artifact, make no changes */
const char *zChngTime; /* The change time on the control artifact */
const char *zUserOvrd; /* The user name on the control artifact */
const char *zUuid;
Blob ctrl;
Blob comment;
char *zNow;
int nTags, nCancels;
int i;
Stmt q;
fEditComment = find_option("edit-comment","e",0)!=0;
zNewComment = find_option("comment","m",1);
zComFile = find_option("message-file","M",1);
zNewBranch = find_option("branch",0,1);
zNewColor = find_option("bgcolor",0,1);
zNewBrColor = find_option("branchcolor",0,1);
| > > > | 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 |
int fHide; /* True if branch should be hidden */
int fPropagateColor; /* True if color propagates before amend */
int fNewPropagateColor = 0; /* True if color propagates after amend */
int fHasHidden = 0; /* True if hidden tag already set */
int fHasClosed = 0; /* True if closed tag already set */
int fEditComment; /* True if editor to be used for comment */
int fDryRun; /* Print control artifact, make no changes */
int noVerifyCom = 0; /* Allow suspicious check-in comments */
const char *zChngTime; /* The change time on the control artifact */
const char *zUserOvrd; /* The user name on the control artifact */
const char *zUuid;
Blob ctrl;
Blob comment;
char *zNow;
int nTags, nCancels;
int i;
Stmt q;
int ckComFlgs; /* Flags passed to verify_comment() */
fEditComment = find_option("edit-comment","e",0)!=0;
zNewComment = find_option("comment","m",1);
zComFile = find_option("message-file","M",1);
zNewBranch = find_option("branch",0,1);
zNewColor = find_option("bgcolor",0,1);
zNewBrColor = find_option("branchcolor",0,1);
|
| ︙ | ︙ | |||
4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 |
pzCancelTags = find_repeatable_option("cancel",0,&nCancels);
fClose = find_option("close",0,0)!=0;
fHide = find_option("hide",0,0)!=0;
fDryRun = find_option("dry-run","n",0)!=0;
zChngTime = find_option("date-override",0,1);
if( zChngTime==0 ) zChngTime = find_option("chngtime",0,1);
zUserOvrd = find_option("user-override",0,1);
db_find_and_open_repository(0,0);
user_select();
verify_all_options();
if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT);
rid = name_to_typed_rid(g.argv[2], "ci");
if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
| > | 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 |
pzCancelTags = find_repeatable_option("cancel",0,&nCancels);
fClose = find_option("close",0,0)!=0;
fHide = find_option("hide",0,0)!=0;
fDryRun = find_option("dry-run","n",0)!=0;
zChngTime = find_option("date-override",0,1);
if( zChngTime==0 ) zChngTime = find_option("chngtime",0,1);
zUserOvrd = find_option("user-override",0,1);
noVerifyCom = find_option("no-verify-comment",0,0)!=0;
db_find_and_open_repository(0,0);
user_select();
verify_all_options();
if( g.argc<3 || g.argc>=4 ) usage(AMEND_USAGE_STMT);
rid = name_to_typed_rid(g.argv[2], "ci");
if( rid==0 && !is_a_version(rid) ) fossil_fatal("no such check-in");
zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
|
| ︙ | ︙ | |||
4072 4073 4074 4075 4076 4077 4078 |
),
fNewPropagateColor
);
}
if( (zNewColor!=0 && zNewColor[0]==0) && (zColor && zColor[0] ) ){
cancel_color();
}
| > > > > > > > > > > > > > > > > | | < | < | | | > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 |
),
fNewPropagateColor
);
}
if( (zNewColor!=0 && zNewColor[0]==0) && (zColor && zColor[0] ) ){
cancel_color();
}
if( fEditComment || zNewComment || zComFile ){
blob_init(&comment, 0, 0);
/* Figure out how much comment verification is requested */
if( noVerifyCom ){
ckComFlgs = 0;
}else{
const char *zVerComs = db_get("verify-comments","on");
if( is_false(zVerComs) ){
ckComFlgs = 0;
}else if( strcmp(zVerComs,"preview")==0 ){
ckComFlgs = COMCK_PREVIEW | COMCK_MARKUP;
}else{
ckComFlgs = COMCK_MARKUP;
}
}
if( fEditComment ){
prepare_amend_comment(&comment, zComment, zUuid);
}else if( zComFile ){
blob_read_from_file(&comment, zComFile, ExtFILE);
blob_to_utf8_no_bom(&comment, 1);
}else if( zNewComment ){
blob_init(&comment, zNewComment, -1);
}
if( blob_size(&comment)>0
&& comment_compare(zComment, blob_str(&comment))==0
){
int rc;
while( (rc = verify_comment(&comment, ckComFlgs))!=0 ){
char cReply;
Blob ans;
if( !fEditComment ){
fossil_fatal("Amend aborted; "
"use --no-verify-comment to override");
}
if( rc==COMCK_PREVIEW ){
prompt_user("Continue, abort, or edit (C/a/e)? ", &ans);
}else{
prompt_user("Edit, abort, or continue (E/a/c)? ", &ans);
}
cReply = blob_str(&ans)[0];
cReply = fossil_tolower(cReply);
blob_reset(&ans);
if( cReply=='a' ){
fossil_fatal("Amend aborted.");
}
if( cReply=='e' || (cReply!='c' && rc!=COMCK_PREVIEW) ){
char *zPrior = blob_materialize(&comment);
blob_init(&comment, 0, 0);
prepare_amend_comment(&comment, zPrior, zUuid);
fossil_free(zPrior);
continue;
}else{
break;
}
}
}
add_comment(blob_str(&comment));
}
if( zNewDate && zNewDate[0] && fossil_strcmp(zDate,zNewDate)!=0 ){
if( is_datetime(zNewDate) ){
add_date(zNewDate);
}else{
fossil_fatal("Unsupported date format, use YYYY-MM-DD HH:MM:SS");
}
}
|
| ︙ | ︙ |
Changes to src/interwiki.c.
| ︙ | ︙ | |||
159 160 161 162 163 164 165 | ** COMMAND: interwiki* ** ** Usage: %fossil interwiki COMMAND ... ** ** Manage the "intermap" that defines the mapping from interwiki tags ** to complete URLs for interwiki links. ** | | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
** COMMAND: interwiki*
**
** Usage: %fossil interwiki COMMAND ...
**
** Manage the "intermap" that defines the mapping from interwiki tags
** to complete URLs for interwiki links.
**
** > fossil interwiki delete TAG ...
**
** Delete one or more interwiki maps.
**
** > fossil interwiki edit TAG --base URL --hash PATH --wiki PATH
**
** Create an interwiki referenced call TAG. The base URL is
** the --base option, which is required. The --hash and --wiki
** paths are optional. The TAG must be lower-case alphanumeric
** and must be unique. A new entry is created if it does not
** already exit.
**
** > fossil interwiki list
**
** Show all interwiki mappings.
*/
void interwiki_cmd(void){
const char *zCmd;
int nCmd;
db_find_and_open_repository(0, 0);
|
| ︙ | ︙ |
Changes to src/json_config.c.
| ︙ | ︙ | |||
84 85 86 87 88 89 90 |
{ "default-skin", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "icon-mimetype", CONFIGSET_SKIN },
{ "icon-image", CONFIGSET_SKIN },
| < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
{ "default-skin", CONFIGSET_SKIN },
{ "logo-mimetype", CONFIGSET_SKIN },
{ "logo-image", CONFIGSET_SKIN },
{ "background-mimetype", CONFIGSET_SKIN },
{ "background-image", CONFIGSET_SKIN },
{ "icon-mimetype", CONFIGSET_SKIN },
{ "icon-image", CONFIGSET_SKIN },
{ "timeline-date-format", CONFIGSET_SKIN },
{ "timeline-default-style", CONFIGSET_SKIN },
{ "timeline-dwelltime", CONFIGSET_SKIN },
{ "timeline-closetime", CONFIGSET_SKIN },
{ "timeline-hard-newlines", CONFIGSET_SKIN },
{ "timeline-max-comment", CONFIGSET_SKIN },
{ "timeline-plaintext", CONFIGSET_SKIN },
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
637 638 639 640 641 642 643 |
}
}
fossil_warning("%s", blob_str(&msg));
blob_reset(&msg);
}
/*
| < | > | | > | 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 |
}
}
fossil_warning("%s", blob_str(&msg));
blob_reset(&msg);
}
/*
** Initialize the g.comFmtFlags global variable.
**
** Global command-line options --comfmtflags or --comment-format can be
** used for this. However, those command-line options are undocumented
** and deprecated. They are here for backwards compatibility only.
*/
static void fossil_init_flags_from_options(void){
const char *zValue = find_option("comfmtflags", 0, 1);
if( zValue==0 ){
zValue = find_option("comment-format", 0, 1);
}
if( zValue ){
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 | fossil_printf_selfcheck(); fossil_limit_memory(1); /* When updating the minimum SQLite version, change the number here, ** and also MINIMUM_SQLITE_VERSION value set in ../auto.def. Take ** care that both places agree! */ | | | | | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 |
fossil_printf_selfcheck();
fossil_limit_memory(1);
/* When updating the minimum SQLite version, change the number here,
** and also MINIMUM_SQLITE_VERSION value set in ../auto.def. Take
** care that both places agree! */
if( sqlite3_libversion_number()<3049000
|| strncmp(sqlite3_sourceid(),"2025-02-06",10)<0
){
fossil_panic("Unsuitable SQLite version %s, must be at least 3.49.0",
sqlite3_libversion());
}
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0);
memset(&g, 0, sizeof(g));
g.now = time(0);
|
| ︙ | ︙ | |||
995 996 997 998 999 1000 1001 |
fossil_fatal("Usage: %s %s %s", g.argv[0], g.argv[1], zFormat);
}
/*
** Remove n elements from g.argv beginning with the i-th element.
*/
static void remove_from_argv(int i, int n){
| < < | < | | 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 |
fossil_fatal("Usage: %s %s %s", g.argv[0], g.argv[1], zFormat);
}
/*
** Remove n elements from g.argv beginning with the i-th element.
*/
static void remove_from_argv(int i, int n){
memmove(&g.argv[i], &g.argv[i+n], sizeof(g.argv[i])*(g.argc-i-n));
g.argc -= n;
}
/*
** Look for a command-line option. If present, remove it from the
** argument list and return a pointer to either the flag's name (if
** hasArg==0), sans leading - or --, or its value (if hasArg==1).
|
| ︙ | ︙ | |||
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 |
zReturn = g.argv[i+hasArg];
remove_from_argv(i, 1+hasArg);
break;
}
}
return zReturn;
}
/* Return true if zOption exists in the command-line arguments,
** but do not remove it from the list or otherwise process it.
*/
int has_option(const char *zOption){
int i;
int n = (int)strlen(zOption);
| > > > > > > > > > | 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
zReturn = g.argv[i+hasArg];
remove_from_argv(i, 1+hasArg);
break;
}
}
return zReturn;
}
/*
** Restore an option previously removed by find_option().
*/
void restore_option(const char *zName, const char *zValue, int hasOpt){
if( zValue==0 && hasOpt ) return;
g.argv[g.argc++] = (char*)zName;
if( hasOpt ) g.argv[g.argc++] = (char*)zValue;
}
/* Return true if zOption exists in the command-line arguments,
** but do not remove it from the list or otherwise process it.
*/
int has_option(const char *zOption){
int i;
int n = (int)strlen(zOption);
|
| ︙ | ︙ | |||
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 |
** then szFile will become zero (for an empty file) or positive.
** Special case: Assume any file with a basename of ".fossil" does
** not exist.
*/
zCleanRepo = file_cleanup_fullpath(zRepo);
if( szFile==0 && sqlite3_strglob("*/.fossil",zRepo)!=0 ){
szFile = file_size(zCleanRepo, ExtFILE);
if( g.fHttpTrace ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", szFile);
@ <!-- file_size(%h(zCleanRepo)) is %s(zBuf) -->
fprintf(stderr, "# file_size(%s) = %s\n", zCleanRepo, zBuf);
}
}
| > > > > > | 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 |
** then szFile will become zero (for an empty file) or positive.
** Special case: Assume any file with a basename of ".fossil" does
** not exist.
*/
zCleanRepo = file_cleanup_fullpath(zRepo);
if( szFile==0 && sqlite3_strglob("*/.fossil",zRepo)!=0 ){
szFile = file_size(zCleanRepo, ExtFILE);
if( szFile>0 && !file_isfile(zCleanRepo, ExtFILE) ){
/* Only let szFile be non-negative if zCleanRepo really is a file
** and not a directory or some other filesystem object. */
szFile = -1;
}
if( g.fHttpTrace ){
sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", szFile);
@ <!-- file_size(%h(zCleanRepo)) is %s(zBuf) -->
fprintf(stderr, "# file_size(%s) = %s\n", zCleanRepo, zBuf);
}
}
|
| ︙ | ︙ | |||
2153 2154 2155 2156 2157 2158 2159 |
json_bootstrap_late();
jsonOnce = 1;
}
}
#endif
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
cgi_decode_post_parameters();
| | | 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 |
json_bootstrap_late();
jsonOnce = 1;
}
}
#endif
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
cgi_decode_post_parameters();
if( !cgi_same_origin(0) ){
isReadonly = 1;
db_protect(PROTECT_READONLY);
}
}
if( g.fCgiTrace ){
fossil_trace("######## Calling %s #########\n", pCmd->zName);
cgi_print_all(1, 1, 0);
|
| ︙ | ︙ | |||
2396 2397 2398 2399 2400 2401 2402 | ** use any other option. ** ** The lines are processed in the order they are read, which is most ** significant for "errorlog:", which should be set before "repository:" ** so that any warnings from the database when opening the repository ** go to that log file. ** | | | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 |
** use any other option.
**
** The lines are processed in the order they are read, which is most
** significant for "errorlog:", which should be set before "repository:"
** so that any warnings from the database when opening the repository
** go to that log file.
**
** See also: [[http]], [[server]], [[winsrv]] [Windows only]
*/
void cmd_cgi(void){
const char *zNotFound = 0;
char **azRedirect = 0; /* List of repositories to redirect to */
int nRedirect = 0; /* Number of entries in azRedirect */
Glob *pFileGlob = 0; /* Pattern for files */
int allowRepoList = 0; /* Allow lists of repository files */
|
| ︙ | ︙ | |||
2528 2529 2530 2531 2532 2533 2534 |
if( blob_eq(&key, "setenv:") && blob_token(&line, &value) ){
/* setenv: NAME VALUE
** setenv: NAME
**
** Sets environment variable NAME to VALUE. If VALUE is omitted, then
** the environment variable is unset.
*/
| > | > > > | | 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 |
if( blob_eq(&key, "setenv:") && blob_token(&line, &value) ){
/* setenv: NAME VALUE
** setenv: NAME
**
** Sets environment variable NAME to VALUE. If VALUE is omitted, then
** the environment variable is unset.
*/
char *zValue;
blob_tail(&line,&value2);
blob_trim(&value2);
zValue = blob_str(&value2);
while( fossil_isspace(zValue[0]) ){ zValue++; }
fossil_setenv(blob_str(&value), zValue);
blob_reset(&value);
blob_reset(&value2);
continue;
}
if( blob_eq(&key, "errorlog:") && blob_token(&line, &value) ){
/* errorlog: FILENAME
**
|
| ︙ | ︙ | |||
2855 2856 2857 2858 2859 2860 2861 |
** --scgi Interpret input as SCGI rather than HTTP
** --skin LABEL Use override skin LABEL. Use an empty string ("")
** to force use of the current local skin config.
** --th-trace Trace TH1 execution (for debugging purposes)
** --usepidkey Use saved encryption key from parent process. This is
** only necessary when using SEE on Windows or Linux.
**
| | | 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 |
** --scgi Interpret input as SCGI rather than HTTP
** --skin LABEL Use override skin LABEL. Use an empty string ("")
** to force use of the current local skin config.
** --th-trace Trace TH1 execution (for debugging purposes)
** --usepidkey Use saved encryption key from parent process. This is
** only necessary when using SEE on Windows or Linux.
**
** See also: [[cgi]], [[server]], [[winsrv]] [Windows only]
*/
void cmd_http(void){
const char *zIpAddr = 0;
const char *zNotFound;
const char *zHost;
const char *zAltBase;
const char *zFileGlob;
|
| ︙ | ︙ | |||
3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 | ** --cert FILE Use TLS (HTTPS) encryption with the certificate (the ** fullchain.pem) taken from FILE. ** --chroot DIR Use directory for chroot instead of repository path ** --ckout-alias NAME Treat URIs of the form /doc/NAME/... as if they were ** /doc/ckout/... ** --create Create a new REPOSITORY if it does not already exist ** --errorlog FILE Append HTTP error messages to FILE ** --extroot DIR Document root for the /ext extension mechanism ** --files GLOBLIST Comma-separated list of glob patterns for static files ** --fossilcmd PATH The pathname of the "fossil" executable on the remote ** system when REPOSITORY is remote. ** --from PATH Use PATH as the diff baseline for the /ckout page ** --localauth Enable automatic login for requests from localhost ** --localhost Listen on 127.0.0.1 only (always true for "ui") | > > > | 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 | ** --cert FILE Use TLS (HTTPS) encryption with the certificate (the ** fullchain.pem) taken from FILE. ** --chroot DIR Use directory for chroot instead of repository path ** --ckout-alias NAME Treat URIs of the form /doc/NAME/... as if they were ** /doc/ckout/... ** --create Create a new REPOSITORY if it does not already exist ** --errorlog FILE Append HTTP error messages to FILE ** --extpage FILE Shortcut for "--extroot DIR --page ext/TAIL" where ** DIR is the directory holding FILE and TAIL is the ** filename at the end of FILE. Only works for "ui". ** --extroot DIR Document root for the /ext extension mechanism ** --files GLOBLIST Comma-separated list of glob patterns for static files ** --fossilcmd PATH The pathname of the "fossil" executable on the remote ** system when REPOSITORY is remote. ** --from PATH Use PATH as the diff baseline for the /ckout page ** --localauth Enable automatic login for requests from localhost ** --localhost Listen on 127.0.0.1 only (always true for "ui") |
| ︙ | ︙ | |||
3237 3238 3239 3240 3241 3242 3243 | ** --socket-owner USR Try to set the owner of the unix socket to USR. ** USR can be of the form USER:GROUP to set both ** user and group. ** --th-trace Trace TH1 execution (for debugging purposes) ** --usepidkey Use saved encryption key from parent process. This is ** only necessary when using SEE on Windows or Linux. ** | | | 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 |
** --socket-owner USR Try to set the owner of the unix socket to USR.
** USR can be of the form USER:GROUP to set both
** user and group.
** --th-trace Trace TH1 execution (for debugging purposes)
** --usepidkey Use saved encryption key from parent process. This is
** only necessary when using SEE on Windows or Linux.
**
** See also: [[cgi]], [[http]], [[winsrv]] [Windows only]
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
const char *zBrowser; /* Name of web browser program */
char *zBrowserCmd = 0; /* Command to launch the web browser */
int isUiCmd; /* True if command is "ui", not "server' */
|
| ︙ | ︙ | |||
3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 | int fNoBrowser = 0; /* Do not auto-launch web-browser */ const char *zInitPage = 0; /* Start on this page. --page option */ int findServerArg = 2; /* argv index for find_server_repository() */ char *zRemote = 0; /* Remote host on which to run "fossil ui" */ const char *zJsMode; /* The --jsmode parameter */ const char *zFossilCmd =0; /* Name of "fossil" binary on remote system */ const char *zFrom; /* Value for --from */ #if USE_SEE db_setup_for_saved_encryption_key(); #endif #if defined(_WIN32) | > | 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 | int fNoBrowser = 0; /* Do not auto-launch web-browser */ const char *zInitPage = 0; /* Start on this page. --page option */ int findServerArg = 2; /* argv index for find_server_repository() */ char *zRemote = 0; /* Remote host on which to run "fossil ui" */ const char *zJsMode; /* The --jsmode parameter */ const char *zFossilCmd =0; /* Name of "fossil" binary on remote system */ const char *zFrom; /* Value for --from */ const char *zExtPage = 0; /* Argument to --extpage */ #if USE_SEE db_setup_for_saved_encryption_key(); #endif #if defined(_WIN32) |
| ︙ | ︙ | |||
3305 3306 3307 3308 3309 3310 3311 |
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
zFrom = find_option("from", 0, 1);
if( zFrom && zFrom==file_tail(zFrom) ){
fossil_fatal("the argument to --from must be a pathname for"
" the \"ui\" command");
}
| > > > > > > > | | > | 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 |
isUiCmd = g.argv[1][0]=='u';
if( isUiCmd ){
zFrom = find_option("from", 0, 1);
if( zFrom && zFrom==file_tail(zFrom) ){
fossil_fatal("the argument to --from must be a pathname for"
" the \"ui\" command");
}
zExtPage = find_option("extpage",0,1);
if( zExtPage ){
char *zFullPath = file_canonical_name_dup(zExtPage);
g.zExtRoot = file_dirname(zFullPath);
zInitPage = mprintf("ext/%s",file_tail(zFullPath));
fossil_free(zFullPath);
}else{
zInitPage = find_option("page", "p", 1);
if( zInitPage && zInitPage[0]=='/' ) zInitPage++;
}
zFossilCmd = find_option("fossilcmd", 0, 1);
if( zFrom && zInitPage==0 ){
zInitPage = mprintf("ckout?exbase=%H", zFrom);
}
}
zNotFound = find_option("notfound", 0, 1);
allowRepoList = find_option("repolist",0,0)!=0;
|
| ︙ | ︙ | |||
3479 3480 3481 3482 3483 3484 3485 |
}else{
blob_appendf(&ssh, " %$", zFossilCmd);
}
blob_appendf(&ssh, " ui --nobrowser --localauth --port %d", iPort);
if( zNotFound ) blob_appendf(&ssh, " --notfound %!$", zNotFound);
if( zFileGlob ) blob_appendf(&ssh, " --files-urlenc %T", zFileGlob);
if( g.zCkoutAlias ) blob_appendf(&ssh," --ckout-alias %!$",g.zCkoutAlias);
| > > > > > > | > | 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 |
}else{
blob_appendf(&ssh, " %$", zFossilCmd);
}
blob_appendf(&ssh, " ui --nobrowser --localauth --port %d", iPort);
if( zNotFound ) blob_appendf(&ssh, " --notfound %!$", zNotFound);
if( zFileGlob ) blob_appendf(&ssh, " --files-urlenc %T", zFileGlob);
if( g.zCkoutAlias ) blob_appendf(&ssh," --ckout-alias %!$",g.zCkoutAlias);
if( zExtPage ){
if( !file_is_absolute_path(zExtPage) ){
zExtPage = mprintf("%s/%s", g.argv[2], zExtPage);
}
blob_appendf(&ssh, " --extpage %$", zExtPage);
}else if( g.zExtRoot ){
blob_appendf(&ssh, " --extroot %$", g.zExtRoot);
}
if( skin_in_use() ) blob_appendf(&ssh, " --skin %s", skin_in_use());
if( zJsMode ) blob_appendf(&ssh, " --jsmode %s", zJsMode);
if( fCreate ) blob_appendf(&ssh, " --create");
blob_appendf(&ssh, " %$", g.argv[2]);
if( isRetry ){
fossil_print("First attempt to run \"fossil\" on %s failed\n"
"Retry: ", zRemote);
|
| ︙ | ︙ | |||
3597 3598 3599 3600 3601 3602 3603 |
if( g.httpUseSSL && g.httpSSLConn ){
ssl_close_server(g.httpSSLConn);
g.httpSSLConn = 0;
}
#endif /* FOSSIL_ENABLE_SSL */
#else /* WIN32 */
| | < | 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 |
if( g.httpUseSSL && g.httpSSLConn ){
ssl_close_server(g.httpSSLConn);
g.httpSSLConn = 0;
}
#endif /* FOSSIL_ENABLE_SSL */
#else /* WIN32 */
/* Win32 implementation */
if( fossil_strcmp(g.zRepositoryName,"/")==0 ){
allowRepoList = 1;
}
if( allowRepoList ){
flags |= HTTP_SERVER_REPOLIST;
}
if( win32_http_service(iPort, zAltBase, zNotFound, zFileGlob, flags) ){
win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile,
zAltBase, zNotFound, zFileGlob, zIpAddr, flags);
}
|
| ︙ | ︙ |
Changes to src/main.mk.
| ︙ | ︙ | |||
2132 2133 2134 2135 2136 2137 2138 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ | | | | > | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 |
$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c
$(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@
$(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST)
$(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \
-sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore \
-sEXPORTED_FUNCTIONS=_pikchr,_pikchr_version $(SRCDIR_extsrc)/pikchr.c \
-sENVIRONMENT=web \
-sMODULARIZE \
-sEXPORT_NAME=initPikchrModule \
--minify 0
$(TCLSH) $(TOPDIR)/tools/randomize-js-names.tcl $(SRCDIR_extsrc)
@chmod -x $(SRCDIR_extsrc)/pikchr.wasm
wasm: $(SRCDIR_extsrc)/pikchr.js
#
# compile_commands.json support...
#
# We have to avoid applying compile_commands support to the in-tree
|
| ︙ | ︙ |
Changes to src/manifest.c.
| ︙ | ︙ | |||
2909 2910 2911 2912 2913 2914 2915 |
Blob content;
db_find_and_open_repository(0, 0);
if( g.argc!=3 ) usage("RECORDID");
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 |
Blob content;
db_find_and_open_repository(0, 0);
if( g.argc!=3 ) usage("RECORDID");
rid = name_to_rid(g.argv[2]);
content_get(rid, &content);
manifest_crosslink(rid, &content, MC_NONE);
}
/*
** For a given CATYPE_... value, returns a human-friendly name, or
** NULL if typeId is unknown or is CFTYPE_ANY. The names returned by
** this function are geared towards use with artifact_to_json(), and
** may differ from some historical uses. e.g. CFTYPE_CONTROL artifacts
** are called "tag" artifacts by this function.
*/
const char * artifact_type_to_name(int typeId){
switch(typeId){
case CFTYPE_MANIFEST: return "checkin";
case CFTYPE_CLUSTER: return "cluster";
case CFTYPE_CONTROL: return "tag";
case CFTYPE_WIKI: return "wiki";
case CFTYPE_TICKET: return "ticket";
case CFTYPE_ATTACHMENT: return "attachment";
case CFTYPE_EVENT: return "technote";
case CFTYPE_FORUM: return "forumpost";
}
return NULL;
}
/*
** Creates a JSON representation of p, appending it to b.
**
** b is not cleared before rendering, so the caller needs to do that
** if it's important for their use case.
**
** Pedantic note: this routine traverses p->aFile directly, rather
** than using manifest_file_next(), so that delta manifests are
** rendered as-is instead of containing their derived F-cards. If that
** policy is ever changed, p will need to be non-const.
*/
void artifact_to_json(Manifest const *p, Blob *b){
int i;
blob_append_literal(b, "{");
blob_appendf(b, "\"uuid\":\"%z\"", rid_to_uuid(p->rid));
/*blob_appendf(b, ", \"rid\": %d", p->rid); not portable across repos*/
blob_appendf(b, ",\"type\":%!j", artifact_type_to_name(p->type));
#define ISA(TYPE) if( p->type==TYPE )
#define CARD_LETTER(LETTER) \
blob_append_literal(b, ",\"" #LETTER "\":")
#define CARD_STR(LETTER, VAL) \
assert( VAL ); CARD_LETTER(LETTER); blob_appendf(b, "%!j", VAL)
#define CARD_STR2(LETTER, VAL) \
if( VAL ) { CARD_STR(LETTER, VAL); } (void)0
#define STR_OR_NULL(VAL) \
if( VAL ) blob_appendf(b, "%!j", VAL); \
else blob_append(b, "null", 4)
#define KVP_STR(ADDCOMMA, KEY,VAL) \
if(ADDCOMMA) blob_append_char(b, ','); \
blob_appendf(b, "%!j:", #KEY); \
STR_OR_NULL(VAL)
ISA( CFTYPE_ATTACHMENT ){
CARD_LETTER(A);
blob_append_char(b, '{');
KVP_STR(0, filename, p->zAttachName);
KVP_STR(1, target, p->zAttachTarget);
KVP_STR(1, source, p->zAttachSrc);
blob_append_char(b, '}');
}
CARD_STR2(B, p->zBaseline);
CARD_STR2(C, p->zComment);
CARD_LETTER(D); blob_appendf(b, "%f", p->rDate);
ISA( CFTYPE_EVENT ){
blob_appendf(b, ", \"E\":{\"time\":%f,\"id\":%!j}",
p->rEventDate, p->zEventId);
}
ISA( CFTYPE_MANIFEST ){
CARD_LETTER(F);
blob_append_char(b, '[');
for( i = 0; i < p->nFile; ++i ){
ManifestFile const * const pF = &p->aFile[i];
if( i>0 ) blob_append_char(b, ',');
blob_append_char(b, '{');
KVP_STR(0, name, pF->zName);
KVP_STR(1, uuid, pF->zUuid);
KVP_STR(1, perm, pF->zPerm);
KVP_STR(1, rename, pF->zPrior);
blob_append_char(b, '}');
}
/* Special case: model checkins with no F-card as having an empty
** array, rather than no F-cards, to hypothetically simplify
** handling in JSON queries. */
blob_append_char(b, ']');
}
CARD_STR2(G, p->zThreadRoot);
ISA( CFTYPE_FORUM ){
CARD_LETTER(H);
STR_OR_NULL( (p->zThreadTitle && *p->zThreadTitle) ? p->zThreadTitle : NULL);
CARD_STR2(I, p->zInReplyTo);
}
if( p->nField ){
CARD_LETTER(J);
blob_append_char(b, '[');
for( i = 0; i < p->nField; ++i ){
const char * zName = p->aField[i].zName;
if( i>0 ) blob_append_char(b, ',');
blob_append_char(b, '{');
KVP_STR(0, name, '+'==*zName ? &zName[1] : zName);
KVP_STR(1, value, p->aField[i].zValue);
blob_appendf(b, ",\"append\":%s", '+'==*zName ? "true" : "false");
blob_append_char(b, '}');
}
blob_append_char(b, ']');
}
CARD_STR2(K, p->zTicketUuid);
CARD_STR2(L, p->zWikiTitle);
ISA( CFTYPE_CLUSTER ){
CARD_LETTER(M);
blob_append_char(b, '[');
for( int i = 0; i < p->nCChild; ++i ){
if( i>0 ) blob_append_char(b, ',');
blob_appendf(b, "%!j", p->azCChild[i]);
}
blob_append_char(b, ']');
}
CARD_STR2(N, p->zMimetype);
ISA( CFTYPE_MANIFEST || p->nParent>0 ){
CARD_LETTER(P);
blob_append_char(b, '[');
for( i = 0; i < p->nParent; ++i ){
if( i>0 ) blob_append_char(b, ',');
blob_appendf(b, "%!j", p->azParent[i]);
}
/* Special case: model checkins with no P-card as having an empty
** array, as per F-cards. */
blob_append_char(b, ']');
}
if( p->nCherrypick ){
CARD_LETTER(Q);
blob_append_char(b, '[');
for( i = 0; i < p->nCherrypick; ++i ){
if( i>0 ) blob_append_char(b, ',');
blob_append_char(b, '{');
blob_appendf(b, "\"type\":\"%c\"", p->aCherrypick[i].zCPTarget[0]);
KVP_STR(1, target, &p->aCherrypick[i].zCPTarget[1]);
KVP_STR(1, base, p->aCherrypick[i].zCPBase);
blob_append_char(b, '}');
}
blob_append_char(b, ']');
}
CARD_STR2(R, p->zRepoCksum);
if( p->nTag ){
CARD_LETTER(T);
blob_append_char(b, '[');
for( int i = 0; i < p->nTag; ++i ){
const char *zName = p->aTag[i].zName;
if( i>0 ) blob_append_char(b, ',');
blob_append_char(b, '{');
blob_appendf(b, "\"type\":\"%c\"", *zName);
KVP_STR(1, name, &zName[1]);
KVP_STR(1, target, p->aTag[i].zUuid ? p->aTag[i].zUuid : "*")
/* We could arguably resolve the "*" as null or p's uuid. */;
KVP_STR(1, value, p->aTag[i].zValue);
blob_append_char(b, '}');
}
blob_append_char(b, ']');
}
CARD_STR2(U, p->zUser);
if( p->zWiki || CFTYPE_WIKI==p->type || CFTYPE_FORUM==p->type
|| CFTYPE_EVENT==p->type ){
CARD_LETTER(W);
STR_OR_NULL((p->zWiki && *p->zWiki) ? p->zWiki : NULL);
}
blob_append_literal(b, "}");
#undef CARD_FMT
#undef CARD_LETTER
#undef CARD_STR
#undef CARD_STR2
#undef ISA
#undef KVP_STR
#undef STR_OR_NULL
}
/*
** Convenience wrapper around artifact_to_json() which expects rid to
** be the blob.rid of any artifact type. If it can load a Manifest
** with that rid, it returns rid, else it returns 0.
*/
int artifact_to_json_by_rid(int rid, Blob *pOut){
Manifest * const p = manifest_get(rid, CFTYPE_ANY, 0);
if( p ){
artifact_to_json(p, pOut);
manifest_destroy(p);
}else{
rid = 0;
}
return rid;
}
/*
** Convenience wrapper around artifact_to_json() which accepts any
** artifact name which is legal for symbolic_name_to_rid(). On success
** it returns the rid of the artifact. Returns 0 if no such artifact
** exists and a negative value if the name is ambiguous.
**
** pOut is not cleared before rendering, so the caller needs to do
** that if it's important for their use case.
*/
int artifact_to_json_by_name(const char *zName, Blob *pOut){
const int rid = symbolic_name_to_rid(zName, 0);
return rid>0
? artifact_to_json_by_rid(rid, pOut)
: rid;
}
/*
** SQLite UDF for artifact_to_json(). Its single argument should be
** either an INTEGER (blob.rid value) or a TEXT symbolic artifact
** name, as per symbolic_name_to_rid(). If an artifact is found then
** the result of the UDF is that JSON as a string, else it evaluates
** to NULL.
*/
void artifact_to_json_sql_func(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
int rid = 0;
Blob b = empty_blob;
if(1 != argc){
goto error_usage;
}
switch( sqlite3_value_type(argv[0]) ){
case SQLITE_INTEGER:
rid = artifact_to_json_by_rid(sqlite3_value_int(argv[0]), &b);
break;
case SQLITE_TEXT:{
const char * z = (const char *)sqlite3_value_text(argv[0]);
if( z ){
rid = artifact_to_json_by_name(z, &b);
}
break;
}
default:
goto error_usage;
}
if( rid>0 ){
sqlite3_result_text(context, blob_str(&b), blob_size(&b),
SQLITE_TRANSIENT);
blob_reset(&b);
}else{
/* We should arguably error out if rid<0 (ambiguous name) */
sqlite3_result_null(context);
}
return;
error_usage:
sqlite3_result_error(context, "Expecting one argument: blob.rid or "
"artifact symbolic name", -1);
}
/*
** COMMAND: test-artifact-to-json
**
** Usage: %fossil test-artifact-to-json ?-pretty|-p? symbolic-name [...names]
**
** Tests the artifact_to_json() and artifact_to_json_by_name() APIs.
*/
void test_manifest_to_json(void){
int i;
Blob b = empty_blob;
Stmt q;
const int bPretty = find_option("pretty","p",0)!=0;
int nErr = 0;
db_find_and_open_repository(0,0);
db_prepare(&q, "select json_pretty(:json)");
for( i=2; i<g.argc; ++i ){
char const *zName = g.argv[i];
const int rc = artifact_to_json_by_name(zName, &b);
if( rc<=0 ){
++nErr;
fossil_warning("Error reading artifact %Q", zName);
continue;
}else if( bPretty ){
db_bind_blob(&q, ":json", &b);
b.nUsed = 0;
db_step(&q);
db_column_blob(&q, 0, &b);
db_reset(&q);
}
fossil_print("%b\n", &b);
blob_reset(&b);
}
db_finalize(&q);
if( nErr ){
fossil_warning("Error count: %d", nErr);
}
}
|
Changes to src/markdown_html.c.
| ︙ | ︙ | |||
909 910 911 912 913 914 915 |
blob_set( &context.reqURI, zRU );
#endif
html_renderer.opaque = &context;
if( output_title ) blob_reset(output_title);
blob_reset(output_body);
markdown(output_body, input_markdown, &html_renderer);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 |
blob_set( &context.reqURI, zRU );
#endif
html_renderer.opaque = &context;
if( output_title ) blob_reset(output_title);
blob_reset(output_body);
markdown(output_body, input_markdown, &html_renderer);
}
/*
** Undo HTML escapes in Blob p. In other words convert:
**
** & -> &
** < -> <
** > -> >
** " -> "
** &#NNN; -> ascii character NNN
*/
void markdown_dehtmlize_blob(Blob *p){
char *z;
unsigned int j, k;
z = p->aData;
for(j=k=0; j<p->nUsed; j++){
char c = z[j];
if( c=='&' ){
if( z[j+1]=='#' && fossil_isdigit(z[j+2]) ){
int n = 3;
int x = z[j+2] - '0';
if( fossil_isdigit(z[j+3]) ){
x = x*10 + z[j+3] - '0';
n++;
if( fossil_isdigit(z[j+4]) ){
x = x*10 + z[j+4] - '0';
n++;
}
}
if( z[j+n]==';' ){
z[k++] = (char)x;
j += n;
}else{
z[k++] = c;
}
}else if( memcmp(&z[j],"<",4)==0 ){
z[k++] = '<';
j += 3;
}else if( memcmp(&z[j],">",4)==0 ){
z[k++] = '>';
j += 3;
}else if( memcmp(&z[j],""",6)==0 ){
z[k++] = '"';
j += 5;
}else if( memcmp(&z[j],"&",5)==0 ){
z[k++] = '&';
j += 4;
}else{
z[k++] = c;
}
}else{
z[k++] = c;
}
}
z[k] = 0;
p->nUsed = k;
}
|
Changes to src/name.c.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 | /* ** Check to see if the string might be a compact date/time that omits ** the punctuation. Example: "20190327084549" instead of ** "2019-03-27 08:45:49". If the string is of the appropriate form, ** then return an alternative string (in static space) that is the same ** string with punctuation inserted. ** ** If the bVerifyNotAHash flag is true, then a check is made to see if | > > > > > > > > > > > > > | | | | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
/*
** Check to see if the string might be a compact date/time that omits
** the punctuation. Example: "20190327084549" instead of
** "2019-03-27 08:45:49". If the string is of the appropriate form,
** then return an alternative string (in static space) that is the same
** string with punctuation inserted.
**
** If the bRoundUp parameter is true, then round the resulting date-time
** up to the largest date/time that is consistent with the input value.
** This is because the result will be used for an mtime<=julianday($DATE)
** comparison. In other words:
**
** 20250317123421 -> 2025-03-17 12:34:21.999
** ^^^^--- Added
**
** 202503171234 -> 2025-03-17 12:34:59.999
** ^^^^^^^--- Added
** 20250317 -> 2025-03-17 23:59:59.999
** ^^^^^^^^^^^^^--- Added
**
** If the bVerifyNotAHash flag is true, then a check is made to see if
** the input string is a hash prefix and NULL is returned if it is. If the
** bVerifyNotAHash flag is false, then the result is determined by syntax
** of the input string only, without reference to the artifact table.
*/
char *fossil_expand_datetime(const char *zIn,int bVerifyNotAHash,int bRoundUp){
static char zEDate[24];
static const char aPunct[] = { 0, 0, '-', '-', ' ', ':', ':' };
int n = (int)strlen(zIn);
int i, j;
int addZulu = 0;
/* These forms are allowed:
**
** 123456789 1234 123456789 123456789 1234
** (1) YYYYMMDD => YYYY-MM-DD 23:59:59.999
** (2) YYYYMMDDHHMM => YYYY-MM-DD HH:MM:59.999
** (3) YYYYMMDDHHMMSS => YYYY-MM-DD HH:MM:SS.999
**
** An optional "Z" zulu timezone designator is allowed at the end.
*/
if( n>0 && (zIn[n-1]=='Z' || zIn[n-1]=='z') ){
n--;
addZulu = 1;
}
|
| ︙ | ︙ | |||
97 98 99 100 101 102 103 |
/* Expand the date */
for(i=j=0; i<n; i++){
if( i>=4 && (i%2)==0 ){
zEDate[j++] = aPunct[i/2];
}
zEDate[j++] = zIn[i];
}
| | | | > > > > > > > > | 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
/* Expand the date */
for(i=j=0; i<n; i++){
if( i>=4 && (i%2)==0 ){
zEDate[j++] = aPunct[i/2];
}
zEDate[j++] = zIn[i];
}
if( bRoundUp ){
if( j==10 ){
memcpy(&zEDate[10], " 23:59:59.999", 13);
j += 13;
}else if( j==16 ){
memcpy(&zEDate[16], ":59.999",7);
j += 7;
}else if( j==19 ){
memcpy(&zEDate[19], ".999", 4);
j += 4;
}
}
if( addZulu ){
zEDate[j++] = 'Z';
}
zEDate[j] = 0;
/* Check for reasonable date values.
** Offset references:
** YYYY-MM-DD HH:MM:SS
|
| ︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 |
** But if the zDate parameter omits the fractional seconds or the
** seconds, or the time, that might mess up the == part of the
** comparison. So add in missing factional seconds or seconds or time.
**
** The returned string is held in a static buffer that is overwritten
** with each call, or else is just a copy of its input if there are
** no changes.
*/
const char *fossil_roundup_date(const char *zDate){
| > > > > > | > > > > > | > | > | > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
** But if the zDate parameter omits the fractional seconds or the
** seconds, or the time, that might mess up the == part of the
** comparison. So add in missing factional seconds or seconds or time.
**
** The returned string is held in a static buffer that is overwritten
** with each call, or else is just a copy of its input if there are
** no changes.
**
** For reference:
**
** 0123456789 123456789 1234
** YYYY-MM-DD HH:MM:SS.SSSz
*/
const char *fossil_roundup_date(const char *zDate){
static char zUp[28];
int n = (int)strlen(zDate);
int addZ = 0;
if( n>10 && (zDate[n-1]=='z' || zDate[n-1]=='Z') ){
n--;
addZ = 1;
}
if( n==19 ){ /* YYYY-MM-DD HH:MM:SS */
memcpy(zUp, zDate, 19);
memcpy(zUp+19, ".999z", 6);
if( !addZ ) zUp[23] = 0;
return zUp;
}
if( n==16 ){ /* YYYY-MM-DD HH:MM */
memcpy(zUp, zDate, 16);
memcpy(zUp+16, ":59.999z", 8);
if( !addZ ) zUp[23] = 0;
return zUp;
}
if( n==10 ){ /* YYYY-MM-DD */
memcpy(zUp, zDate, 10);
memcpy(zUp+10, " 23:59:59.999z", 14);
if( !addZ ) zUp[23] = 0;
return zUp;
}
return zDate;
}
/*
|
| ︙ | ︙ | |||
229 230 231 232 233 234 235 | ** Return 0 if there are no matches. ** ** This is a tricky query to do efficiently. ** If the tag is very common (ex: "trunk") then ** we want to use the query identified below as Q1 - which searches ** the most recent EVENT table entries for the most recent with the tag. ** But if the tag is relatively scarce (anything other than "trunk", basically) | | | 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
** Return 0 if there are no matches.
**
** This is a tricky query to do efficiently.
** If the tag is very common (ex: "trunk") then
** we want to use the query identified below as Q1 - which searches
** the most recent EVENT table entries for the most recent with the tag.
** But if the tag is relatively scarce (anything other than "trunk", basically)
** then we want to do the indexed search shown below as Q2.
*/
static int most_recent_event_with_tag(const char *zTag, const char *zType){
return db_int(0,
"SELECT objid FROM ("
/* Q1: Begin by looking for the tag in the 30 most recent events */
"SELECT objid"
" FROM (SELECT * FROM event ORDER BY mtime DESC LIMIT 30) AS ex"
|
| ︙ | ︙ | |||
477 478 479 480 481 482 483 |
g.localOpen = ridCkout;
}
if( rid ) return rid;
}
/* Date and times */
if( memcmp(zTag, "date:", 5)==0 ){
| | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
g.localOpen = ridCkout;
}
if( rid ) return rid;
}
/* Date and times */
if( memcmp(zTag, "date:", 5)==0 ){
zDate = fossil_expand_datetime(&zTag[5],0,1);
if( zDate==0 ) zDate = &zTag[5];
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
fossil_roundup_date(zDate), zType);
return rid;
|
| ︙ | ︙ | |||
543 544 545 546 547 548 549 |
return start_of_branch(rid, 2);
}
/* symbolic-name ":" date-time */
nTag = strlen(zTag);
for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
if( zTag[i]==':'
| | | | 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
return start_of_branch(rid, 2);
}
/* symbolic-name ":" date-time */
nTag = strlen(zTag);
for(i=0; i<nTag-8 && zTag[i]!=':'; i++){}
if( zTag[i]==':'
&& (fossil_isdate(&zTag[i+1]) || fossil_expand_datetime(&zTag[i+1],0,0)!=0)
){
char *zDate = mprintf("%s", &zTag[i+1]);
char *zTagBase = mprintf("%.*s", i, zTag);
char *zXDate;
int nDate = strlen(zDate);
if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){
zDate[nDate-3] = 'z';
zDate[nDate-2] = 0;
}
zXDate = fossil_expand_datetime(zDate,0,1);
if( zXDate==0 ) zXDate = zDate;
rid = db_int(0,
"SELECT event.objid, max(event.mtime)"
" FROM tag, tagxref, event"
" WHERE tag.tagname='sym-%q' "
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 "
" AND event.objid=tagxref.rid "
|
| ︙ | ︙ | |||
629 630 631 632 633 634 635 |
if( rid>0 ){
if( startOfBranch ) rid = start_of_branch(rid,1);
return rid;
}
/* Pure numeric date/time */
| | | 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
if( rid>0 ){
if( startOfBranch ) rid = start_of_branch(rid,1);
return rid;
}
/* Pure numeric date/time */
zDate = fossil_expand_datetime(zTag, 0,1);
if( zDate ){
rid = db_int(0,
"SELECT objid FROM event"
" WHERE mtime<=julianday(%Q,fromLocal()) AND type GLOB '%q'"
" ORDER BY mtime DESC LIMIT 1",
fossil_roundup_date(zDate), zType);
if( rid) return rid;
|
| ︙ | ︙ | |||
682 683 684 685 686 687 688 689 690 691 692 693 694 695 |
){
char *zNew = fossil_strndup(zTag, nTag-2);
rid = symbolic_name_to_rid(zNew,zType);
fossil_free(zNew);
}
return rid;
}
/*
** This routine takes a user-entered string and tries to convert it to
** an artifact hash.
**
** We first try to treat the string as an artifact hash, or at least a
** unique prefix of an artifact hash. The input may be in mixed case.
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 |
){
char *zNew = fossil_strndup(zTag, nTag-2);
rid = symbolic_name_to_rid(zNew,zType);
fossil_free(zNew);
}
return rid;
}
/*
** Convert a symbolic name used as an argument to the a=, b=, or c=
** query parameters of timeline into a julianday mtime value.
**
** If pzDisplay is not null, then display text for the symbolic name might
** be written into *pzDisplay. But that is not guaranteed.
**
** If bRoundUp is true and the symbolic name is a timestamp with less
** than millisecond resolution, then the timestamp is rounding up to the
** largest millisecond consistent with that timestamp. If bRoundUp is
** false, then the resulting time is obtained by extending the timestamp
** with zeros (hence rounding down). Use bRoundUp==1 if the result
** will be used in mtime<=$RESULT and use bRoundUp==0 if the result
** will be used in mtime>=$RESULT.
*/
double symbolic_name_to_mtime(
const char *z, /* Input symbolic name */
const char **pzDisplay, /* Perhaps write display text here, if not NULL */
int bRoundUp /* Round up if true */
){
double mtime;
int rid;
const char *zDate;
if( z==0 ) return -1.0;
if( fossil_isdate(z) ){
mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())", z);
if( mtime>0.0 ) return mtime;
}
zDate = fossil_expand_datetime(z, 1, bRoundUp);
if( zDate!=0 ){
mtime = db_double(0.0, "SELECT julianday(%Q,fromLocal())",
bRoundUp ? fossil_roundup_date(zDate) : zDate);
if( mtime>0.0 ){
if( pzDisplay ){
zDate = fossil_expand_datetime(z,0,0);
*pzDisplay = fossil_strdup(zDate);
}
return mtime;
}
}
rid = symbolic_name_to_rid(z, "*");
if( rid ){
mtime = mtime_of_rid(rid, 0.0);
}else{
mtime = db_double(-1.0,
"SELECT max(event.mtime) FROM event, tag, tagxref"
" WHERE tag.tagname GLOB 'event-%q*'"
" AND tagxref.tagid=tag.tagid AND tagxref.tagtype"
" AND event.objid=tagxref.rid",
z
);
}
return mtime;
}
/*
** This routine takes a user-entered string and tries to convert it to
** an artifact hash.
**
** We first try to treat the string as an artifact hash, or at least a
** unique prefix of an artifact hash. The input may be in mixed case.
|
| ︙ | ︙ |
Changes to src/patch.c.
| ︙ | ︙ | |||
696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
}
if( zDir && file_chdir(zDir,0) ){
fossil_fatal("cannot change to directory \"%s\"", zDir);
}
fossil_free(zToFree);
return zPatchFile;
}
/*
** Create a FILE* that will execute the remote side of a push or pull
** using ssh (probably) or fossil for local pushes and pulls. Return
** a FILE* obtained from popen() into which we write the patch, or from
** which we read the patch, depending on whether this is a push or pull.
*/
| > > > > > > > > > > > > > > > > | 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 |
}
if( zDir && file_chdir(zDir,0) ){
fossil_fatal("cannot change to directory \"%s\"", zDir);
}
fossil_free(zToFree);
return zPatchFile;
}
/*
** Resolves a patch-command remote system name, accounting for patch
** aliases.
**
** If a CONFIG table entry matching name='patch-alias:$zKey' is found,
** the corresponding value is returned, else a fossil_strdup() of zKey
** is returned. The caller is responsible for passing the resulting
** string to fossil_free().
*/
static char *patch_resolve_remote(const char *zKey){
char *zAlias = db_text(0, "SELECT value FROM config "
"WHERE name = 'patch-alias:%q'",
zKey);
return zAlias ? zAlias : fossil_strdup(zKey);
}
/*
** Create a FILE* that will execute the remote side of a push or pull
** using ssh (probably) or fossil for local pushes and pulls. Return
** a FILE* obtained from popen() into which we write the patch, or from
** which we read the patch, depending on whether this is a push or pull.
*/
|
| ︙ | ︙ | |||
727 728 729 730 731 732 733 |
if( mFlags & PATCH_FORCE ) blob_appendf(&flgs, " -f");
if( mFlags & PATCH_VERBOSE ) blob_appendf(&flgs, " -v");
if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
if( g.argc!=4 ){
usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
}
| | | 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
if( mFlags & PATCH_FORCE ) blob_appendf(&flgs, " -f");
if( mFlags & PATCH_VERBOSE ) blob_appendf(&flgs, " -v");
if( mFlags & PATCH_DRYRUN ) blob_appendf(&flgs, " -n");
zForce = blob_size(&flgs)>0 ? blob_str(&flgs) : "";
if( g.argc!=4 ){
usage(mprintf("%s [USER@]HOST:DIRECTORY", zThisCmd));
}
zRemote = patch_resolve_remote(g.argv[3]);
zDir = (char*)file_skip_userhost(zRemote);
if( zDir==0 ){
if( isRetry ) goto remote_command_error;
zDir = zRemote;
blob_append_escaped_arg(&cmd, g.nameOfExe, 1);
blob_appendf(&cmd, " patch %s%s %$ -", zRemoteCmd, zForce, zDir);
}else{
|
| ︙ | ︙ | |||
776 777 778 779 780 781 782 |
}
/*
** Toggle the use-path-for-ssh setting for the remote host defined
** by g.argv[3].
*/
static void patch_toggle_ssh_needs_path(void){
| | | 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
}
/*
** Toggle the use-path-for-ssh setting for the remote host defined
** by g.argv[3].
*/
static void patch_toggle_ssh_needs_path(void){
char *zRemote = patch_resolve_remote(g.argv[3]);
char *zDir = (char*)file_skip_userhost(zRemote);
if( zDir ){
*(char*)(zDir - 1) = 0;
ssh_needs_path_argument(zRemote, 99);
}
fossil_free(zRemote);
}
|
| ︙ | ︙ | |||
903 904 905 906 907 908 909 |
}
}
db_finalize(&q);
diff_end(pCfg, nErr);
if( nErr ) fossil_fatal("abort due to prior errors");
}
| < > > > > > > > > > > > > | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
}
}
db_finalize(&q);
diff_end(pCfg, nErr);
if( nErr ) fossil_fatal("abort due to prior errors");
}
/*
** COMMAND: patch
**
** Usage: %fossil patch SUBCOMMAND ?ARGS ..?
**
** This command is used to create, view, and apply Fossil binary patches.
** A Fossil binary patch is a single (binary) file that captures all of the
** uncommitted changes of a check-out. Use Fossil binary patches to transfer
** proposed or incomplete changes between machines for testing or analysis.
**
** > fossil patch alias add|rm|ls|list ?ARGS?
**
** Manage remote-name aliases, which act as short-form
** equivalents to REMOTE-CHECKOUT strings. Aliases are local to
** a given repository and do not sync. Subcommands:
**
** ... add ALIAS REMOTE-CHECKOUT Add ALIAS as an alias
** for REMOTE-CHECKOUT.
** ... ls|list List all local aliases.
** ... rm ALIAS [ALIAS...] Remove named aliases
** ... rm --all Remove all aliases
**
** > fossil patch create [DIRECTORY] PATCHFILE
**
** Create a new binary patch in PATCHFILE that captures all uncommitted
** changes in the check-out at DIRECTORY, or the current directory if
** DIRECTORY is omitted. If PATCHFILE is "-" then the binary patch
** is written to standard output.
**
|
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 |
**
*/
void patch_cmd(void){
const char *zCmd;
size_t n;
if( g.argc<3 ){
patch_usage:
| | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 |
**
*/
void patch_cmd(void){
const char *zCmd;
size_t n;
if( g.argc<3 ){
patch_usage:
usage("alias|apply|create|diff|gdiff|pull|push|view");
}
zCmd = g.argv[2];
n = strlen(zCmd);
if( strncmp(zCmd, "alias", n)==0 ){
const char * zArg = g.argc>3 ? g.argv[3] : 0;
db_must_be_within_tree();
if( 0==zArg ){
goto usage_patch_alias;
}else if( 0==strcmp("ls",zArg) || 0==strcmp("list",zArg) ){
/* alias ls|list */
Stmt q;
int nAlias = 0;
verify_all_options();
db_prepare(&q, "SELECT substr(name,13), value FROM config "
"WHERE name GLOB 'patch-alias:*' ORDER BY name");
while( SQLITE_ROW==db_step(&q) ){
const char *zName = db_column_text(&q, 0);
const char *zVal = db_column_text(&q, 1);
++nAlias;
fossil_print("%s = %s\n", zName, zVal);
}
db_finalize(&q);
if( 0==nAlias ){
fossil_print("No patch aliases defined\n");
}
}else if( 0==strcmp("add", zArg) ){
/* alias add localName remote */
verify_all_options();
if( 6!=g.argc ){
usage("alias add localName remote");
}
db_unprotect(PROTECT_CONFIG);
db_multi_exec("REPLACE INTO config (name, value, mtime) "
"VALUES ('patch-alias:%q', %Q, unixepoch())",
g.argv[4], g.argv[5]);
db_protect_pop();
}else if( 0==strcmp("rm", zArg) ){
/* alias rm */
const int fAll = 0!=find_option("all", 0, 0);
if( fAll ? g.argc<4 : g.argc<5 ){
usage("alias rm [-all] [aliasGlob [...aliasGlobN]]");
}
verify_all_options();
db_unprotect(PROTECT_CONFIG);
if( 0!=fAll ){
db_multi_exec("DELETE FROM config WHERE name GLOB 'patch-alias:*'");
}else{
Stmt q;
int i;
db_prepare(&q, "DELETE FROM config WHERE name "
"GLOB 'patch-alias:' || :pattern");
for(i = 4; i < g.argc; ++i){
db_bind_text(&q, ":pattern", g.argv[i]);
db_step(&q);
db_reset(&q);
}
db_finalize(&q);
}
db_protect_pop();
}else{
usage_patch_alias:
usage("alias ls|list|add|rm ...");
}
}else
if( strncmp(zCmd, "apply", n)==0 ){
char *zIn;
unsigned flags = 0;
if( find_option("dry-run","n",0) ) flags |= PATCH_DRYRUN;
if( find_option("verbose","v",0) ) flags |= PATCH_VERBOSE;
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
zIn = patch_find_patch_filename("apply");
|
| ︙ | ︙ | |||
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 |
if( find_option("tk",0,0)!=0 ){
db_close(0);
diff_tk("patch diff", 3);
return;
}
db_find_and_open_repository(0, 0);
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
diff_options(&DCfg, zCmd[0]=='g', 0);
verify_all_options();
| > > > > | | 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
if( find_option("tk",0,0)!=0 ){
db_close(0);
diff_tk("patch diff", 3);
return;
}
db_find_and_open_repository(0, 0);
if( gdiff_using_tk(zCmd[0]=='g') ){
diff_tk("patch diff", 3);
return;
}
if( find_option("force","f",0) ) flags |= PATCH_FORCE;
diff_options(&DCfg, zCmd[0]=='g', 0);
verify_all_options();
zIn = patch_find_patch_filename("diff");
patch_attach(zIn, stdin, 0);
patch_diff(flags, &DCfg);
fossil_free(zIn);
}else
if( strncmp(zCmd, "pull", n)==0 ){
FILE *pIn = 0;
unsigned flags = 0;
|
| ︙ | ︙ |
Changes to src/path.c.
| ︙ | ︙ | |||
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
**
** This file contains code used to trace paths of through the
** directed acyclic graph (DAG) of check-ins.
*/
#include "config.h"
#include "path.h"
#include <assert.h>
#if INTERFACE
/* Nodes for the paths through the DAG.
*/
struct PathNode {
int rid; /* ID for this node */
u8 fromIsParent; /* True if pFrom is the parent of rid */
u8 isPrim; /* True if primary side of common ancestor */
u8 isHidden; /* Abbreviate output in "fossil bisect ls" */
PathNode *pFrom; /* Node we came from */
union {
| > > > | | | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | | > > > > > | > > > > > > > > > | > > | > | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
**
** This file contains code used to trace paths of through the
** directed acyclic graph (DAG) of check-ins.
*/
#include "config.h"
#include "path.h"
#include <assert.h>
#include <math.h>
#if INTERFACE
/* Nodes for the paths through the DAG.
*/
struct PathNode {
int rid; /* ID for this node */
u8 fromIsParent; /* True if pFrom is the parent of rid */
u8 isPrim; /* True if primary side of common ancestor */
u8 isHidden; /* Abbreviate output in "fossil bisect ls" */
char *zBranch; /* Branch name for this node. Might be NULL */
double mtime; /* Date/time of this check-in */
PathNode *pFrom; /* Node we came from */
union {
double rCost; /* Cost of getting to this node from pStart */
PathNode *pTo; /* Next on path from beginning to end */
} u;
PathNode *pAll; /* List of all nodes */
};
#endif
/*
** Local variables for this module
*/
static struct {
PQueue pending; /* Nodes pending review for inclusion in the graph */
PathNode *pAll; /* All nodes */
int nStep; /* Number of steps from first to last */
int nNotHidden; /* Number of steps not counting hidden nodes */
int brCost; /* Extra cost for moving to a different branch */
int revCost; /* Extra cost for changing directions */
PathNode *pStart; /* Earliest node */
PathNode *pEnd; /* Most recent */
} path;
static int path_debug = 0; /* Flag to enable debugging */
/*
** Return the first (last) element of the computed path.
*/
PathNode *path_first(void){ return path.pStart; }
PathNode *path_last(void){ return path.pEnd; }
/*
** Return the number of steps in the computed path.
*/
int path_length(void){ return path.nStep; }
/*
** Return the number of non-hidden steps in the computed path.
*/
int path_length_not_hidden(void){ return path.nNotHidden; }
/*
** Used for debugging only.
**
** Given a RID, return the ISO date/time string and branch for the
** corresponding check-in. Memory is held locally and is overwritten
** with each call.
*/
char *path_rid_desc(int rid){
static Stmt q;
static char *zDesc = 0;
db_static_prepare(&q,
"SELECT concat(strftime('%%Y%%m%%d%%H%%M',event.mtime),'/',value)"
" FROM event, tagxref"
" WHERE event.objid=:rid"
" AND tagxref.rid=:rid"
" AND tagxref.tagid=%d"
" AND tagxref.tagtype>0",
TAG_BRANCH
);
fossil_free(zDesc);
db_bind_int(&q, ":rid", rid);
if( db_step(&q)==SQLITE_ROW ){
zDesc = fossil_strdup(db_column_text(&q,0));
}
db_reset(&q);
return zDesc ? zDesc : "???";
}
/*
** Create a new node and insert it into the path.pending queue.
*/
static PathNode *path_new_node(int rid, PathNode *pFrom, int isParent){
PathNode *p;
p = fossil_malloc( sizeof(*p) );
memset(p, 0, sizeof(*p));
p->pAll = path.pAll;
path.pAll = p;
p->rid = rid;
p->fromIsParent = isParent;
p->pFrom = pFrom;
p->u.rCost = pFrom ? pFrom->u.rCost : 0.0;
if( path.brCost ){
p->zBranch = branch_of_rid(rid);
p->mtime = mtime_of_rid(rid, 0.0);
if( pFrom ){
p->u.rCost += fabs(pFrom->mtime - p->mtime);
if( fossil_strcmp(p->zBranch, pFrom->zBranch)!=0 ){
p->u.rCost += path.brCost;
}
}
}else{
/* When brCost==0, we try to minimize the number of nodes
** along the path. The cost is just the number of nodes back
** to the start. We do not need to know the branch name nor
** the mtime */
p->u.rCost += 1.0;
}
if( path_debug ){
fossil_print("PUSH %-50s cost = %g\n", path_rid_desc(p->rid), p->u.rCost);
}
pqueuex_insert_ptr(&path.pending, (void*)p, p->u.rCost);
return p;
}
/*
** Reset memory used by the shortest path algorithm.
*/
void path_reset(void){
PathNode *p;
while( path.pAll ){
p = path.pAll;
path.pAll = p->pAll;
fossil_free(p->zBranch);
fossil_free(p);
}
pqueuex_clear(&path.pending);
memset(&path, 0, sizeof(path));
}
/*
** Construct the path from path.pStart to path.pEnd in the u.pTo fields.
*/
static void path_reverse_path(void){
|
| ︙ | ︙ | |||
126 127 128 129 130 131 132 | ** Return NULL if no path is found. */ PathNode *path_shortest( int iFrom, /* Path starts here */ int iTo, /* Path ends here */ int directOnly, /* No merge links if true */ int oneWayOnly, /* Parent->child only if true */ | | > < > > | | | | | < < | < < < < < < > | | | | | | | | | > > > > > > > > > > > | | < < | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
** Return NULL if no path is found.
*/
PathNode *path_shortest(
int iFrom, /* Path starts here */
int iTo, /* Path ends here */
int directOnly, /* No merge links if true */
int oneWayOnly, /* Parent->child only if true */
Bag *pHidden, /* Hidden nodes */
int branchCost /* Add extra cost to changing branches */
){
Stmt s;
Bag seen;
PathNode *p;
path_reset();
path.brCost = branchCost;
path.pStart = path_new_node(iFrom, 0, 0);
if( iTo==iFrom ){
path.pEnd = path.pStart;
return path.pStart;
}
if( oneWayOnly && directOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim"
);
}else if( oneWayOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid "
);
}else if( directOnly ){
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid AND isprim "
"UNION ALL "
"SELECT pid, 0 FROM plink WHERE :back AND cid=:pid AND isprim"
);
}else{
db_prepare(&s,
"SELECT cid, 1 FROM plink WHERE pid=:pid "
"UNION ALL "
"SELECT pid, 0 FROM plink WHERE :back AND cid=:pid"
);
}
bag_init(&seen);
while( (p = pqueuex_extract_ptr(&path.pending))!=0 ){
if( path_debug ){
printf("PULL %s %g\n", path_rid_desc(p->rid), p->u.rCost);
}
if( p->rid==iTo ){
db_finalize(&s);
path.pEnd = p;
path_reverse_path();
for(p=path.pStart->u.pTo; p; p=p->u.pTo ){
if( !p->isHidden ) path.nNotHidden++;
}
return path.pStart;
}
if( bag_find(&seen, p->rid) ) continue;
bag_insert(&seen, p->rid);
db_bind_int(&s, ":pid", p->rid);
if( !oneWayOnly ) db_bind_int(&s, ":back", !p->fromIsParent);
while( db_step(&s)==SQLITE_ROW ){
int cid = db_column_int(&s, 0);
int isParent = db_column_int(&s, 1);
PathNode *pNew;
if( bag_find(&seen, cid) ) continue;
pNew = path_new_node(cid, p, isParent);
if( pHidden && bag_find(pHidden,cid) ) pNew->isHidden = 1;
}
db_reset(&s);
}
db_finalize(&s);
path_reset();
return 0;
}
/*
|
| ︙ | ︙ | |||
213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
*/
PathNode *path_next(void){
PathNode *p;
p = path.pStart;
if( p ) p = p->u.pTo;
return p;
}
/*
** Return an estimate of the number of comparisons remaining in order
** to bisect path. This is based on the log2() of path.nStep.
*/
int path_search_depth(void){
int i, j;
| > > > > > > > > > > > > | 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
*/
PathNode *path_next(void){
PathNode *p;
p = path.pStart;
if( p ) p = p->u.pTo;
return p;
}
/*
** Return the branch for a path node.
**
** Storage space is managed by the path subsystem. The returned value
** is valid until the path is reset.
*/
const char *path_branch(PathNode *p){
if( p==0 ) return 0;
if( p->zBranch==0 ) p->zBranch = branch_of_rid(p->rid);
return p->zBranch;
}
/*
** Return an estimate of the number of comparisons remaining in order
** to bisect path. This is based on the log2() of path.nStep.
*/
int path_search_depth(void){
int i, j;
|
| ︙ | ︙ | |||
236 237 238 239 240 241 242 |
void path_shortest_stored_in_ancestor_table(
int origid, /* RID for check-in at start of the path */
int cid /* RID for check-in at the end of the path */
){
PathNode *pPath;
int gen = 0;
Stmt ins;
| | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
void path_shortest_stored_in_ancestor_table(
int origid, /* RID for check-in at start of the path */
int cid /* RID for check-in at the end of the path */
){
PathNode *pPath;
int gen = 0;
Stmt ins;
pPath = path_shortest(cid, origid, 1, 0, 0, 0);
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ancestor("
" rid INT UNIQUE,"
" generation INTEGER PRIMARY KEY"
");"
"DELETE FROM ancestor;"
);
|
| ︙ | ︙ | |||
259 260 261 262 263 264 265 | db_finalize(&ins); path_reset(); } /* ** COMMAND: test-shortest-path ** | | | > > > > | > > > > | > < < < < < < < < < < < < | | < > | < < < | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
db_finalize(&ins);
path_reset();
}
/*
** COMMAND: test-shortest-path
**
** Usage: %fossil test-shortest-path [OPTIONS] VERSION1 VERSION2
**
** Report the shortest path between two check-ins. Options:
**
** --branch-cost N Additional cost N for changing branches
** --debug Show debugging output
** --one-way One-way forwards in time, parent->child only
** --no-merge Follow only direct parent-child paths and omit
** merge links.
*/
void shortest_path_test_cmd(void){
int iFrom;
int iTo;
PathNode *p;
int n;
int directOnly;
int oneWay;
const char *zBrCost;
db_find_and_open_repository(0,0);
directOnly = find_option("no-merge",0,0)!=0;
oneWay = find_option("one-way",0,0)!=0;
zBrCost = find_option("branch-cost",0,1);
if( find_option("debug",0,0)!=0 ) path_debug = 1;
if( g.argc!=4 ) usage("VERSION1 VERSION2");
iFrom = name_to_rid(g.argv[2]);
iTo = name_to_rid(g.argv[3]);
p = path_shortest(iFrom, iTo, directOnly, oneWay, 0,
zBrCost ? atoi(zBrCost) : 0);
if( p==0 ){
fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
}
for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
fossil_print("%4d: %s\n", n, path_rid_desc(p->rid));
}
path_debug = 0;
}
/*
** Find the closest common ancestor of two nodes. "Closest" means the
** fewest number of arcs.
*/
int path_common_ancestor(int iMe, int iYou){
Stmt s;
PathNode *pThis;
PathNode *p;
Bag me, you;
if( iMe==iYou ) return iMe;
if( iMe==0 || iYou==0 ) return 0;
path_reset();
path.pStart = path_new_node(iMe, 0, 0);
path.pStart->isPrim = 1;
path.pEnd = path_new_node(iYou, 0, 0);
db_prepare(&s, "SELECT pid FROM plink WHERE cid=:cid");
bag_init(&me);
bag_insert(&me, iMe);
bag_init(&you);
bag_insert(&you, iYou);
while( (pThis = pqueuex_extract_ptr(&path.pending))!=0 ){
db_bind_int(&s, ":cid", pThis->rid);
while( db_step(&s)==SQLITE_ROW ){
int pid = db_column_int(&s, 0);
if( bag_find(pThis->isPrim ? &you : &me, pid) ){
/* pid is the common ancestor */
PathNode *pNext;
for(p=path.pAll; p && p->rid!=pid; p=p->pAll){}
assert( p!=0 );
pNext = p;
while( pNext ){
pNext = p->pFrom;
p->pFrom = pThis;
pThis = p;
p = pNext;
}
if( pThis==path.pStart ) path.pStart = path.pEnd;
path.pEnd = pThis;
path_reverse_path();
db_finalize(&s);
return pid;
}else if( bag_find(pThis->isPrim ? &me : &you, pid) ){
/* pid is just an alternative path to a node we've already visited */
continue;
}
p = path_new_node(pid, pThis, 0);
p->isPrim = pThis->isPrim;
bag_insert(pThis->isPrim ? &me : &you, pid);
}
db_reset(&s);
}
db_finalize(&s);
path_reset();
return 0;
}
/*
|
| ︙ | ︙ | |||
451 452 453 454 455 456 457 |
if(0==iFrom){
fossil_fatal("Invalid 'from' RID: 0");
}else if(0==iTo){
fossil_fatal("Invalid 'to' RID: 0");
}
if( iFrom==iTo ) return;
path_reset();
| | | 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
if(0==iFrom){
fossil_fatal("Invalid 'from' RID: 0");
}else if(0==iTo){
fossil_fatal("Invalid 'to' RID: 0");
}
if( iFrom==iTo ) return;
path_reset();
p = path_shortest(iFrom, iTo, 1, revOK==0, 0, 0);
if( p==0 ) return;
path_reverse_path();
db_prepare(&q1,
"SELECT pfnid, fnid FROM mlink"
" WHERE mid=:mid AND (pfnid>0 OR fid==0)"
" ORDER BY pfnid"
);
|
| ︙ | ︙ |
Changes to src/pqueue.c.
| ︙ | ︙ | |||
13 14 15 16 17 18 19 | ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to implement a priority queue. ** A priority queue is a list of items order by a floating point | | | > < < | > > > > > > > > | > | > > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code used to implement a priority queue.
** A priority queue is a list of items order by a floating point
** value. Each value can be associated with either a pointer or
** an integer. Items are inserted into the queue in an arbitrary
** order, but are returned in order of the floating point value.
**
** This implementation uses a heap of QueueElement objects. The
** root of the heap is PQueue.a[0]. Each node a[x] has two daughter
** nodes a[x*2+1] and a[x*2+2]. The mother node of a[y] is a[(y-1)/2]
** (assuming integer division rounded down). The following is always true:
**
** The value of any node is less than or equal two the values
** of both daughter nodes. (The Heap Property).
**
** A consequence of the heap property is that a[0] always contains
** the node with the smallest value.
**
** Compatibility note: Some versions of OpenSSL export a symbols
** like "pqueue_insert". This is, technically, a bug in OpenSSL.
** We work around it here by using "pqueuex_" instead of "pqueue_".
*/
#include "config.h"
#include "pqueue.h"
#include <assert.h>
#if INTERFACE
/*
** An integer can appear in the bag at most once.
** Integers must be positive.
*/
struct PQueue {
int cnt; /* Number of entries in the queue */
int sz; /* Number of slots in a[] */
struct QueueElement {
union {
int id; /* ID of the element */
void *p; /* Pointer to an object */
} u;
double value; /* Value of element. Kept in ascending order */
} *a;
};
#endif
/*
** Initialize a PQueue structure
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 74 75 76 77 78 79 |
/*
** Change the size of the queue so that it contains N slots
*/
static void pqueuex_resize(PQueue *p, int N){
p->a = fossil_realloc(p->a, sizeof(p->a[0])*N);
p->sz = N;
}
/*
** Insert element e into the queue.
*/
void pqueuex_insert(PQueue *p, int e, double v){
int i, j;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < | > | < > > | > | < < < < < < | | | | | > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
/*
** Change the size of the queue so that it contains N slots
*/
static void pqueuex_resize(PQueue *p, int N){
p->a = fossil_realloc(p->a, sizeof(p->a[0])*N);
p->sz = N;
}
/*
** Allocate a new queue entry and return a pointer to it.
*/
static struct QueueElement *pqueuex_new_entry(PQueue *p){
if( p->cnt+1>p->sz ){
pqueuex_resize(p, p->cnt+7);
}
return &p->a[p->cnt++];
}
/*
** Element p->a[p->cnt-1] has just been inserted. Shift entries
** around so as to preserve the heap property.
*/
static void pqueuex_rebalance(PQueue *p){
int i, j;
struct QueueElement *a = p->a;
i = p->cnt-1;
while( (j = (i-1)/2)>=0 && a[j].value>a[i].value ){
struct QueueElement t = a[j];
a[j] = a[i];
a[i] = t;
i = j;
}
}
/*
** Insert element e into the queue.
*/
void pqueuex_insert(PQueue *p, int e, double v){
struct QueueElement *pE = pqueuex_new_entry(p);
pE->value = v;
pE->u.id = e;
pqueuex_rebalance(p);
}
void pqueuex_insert_ptr(PQueue *p, void *pPtr, double v){
struct QueueElement *pE = pqueuex_new_entry(p);
pE->value = v;
pE->u.p = pPtr;
pqueuex_rebalance(p);
}
/*
** Remove and discard p->a[0] element from the queue. Rearrange
** nodes to preserve the heap property.
*/
static void pqueuex_pop(PQueue *p){
int i, j;
struct QueueElement *a = p->a;
struct QueueElement tmp;
i = 0;
a[0] = a[p->cnt-1];
p->cnt--;
while( (j = i*2+1)<p->cnt ){
if( j+1<p->cnt && a[j].value > a[j+1].value ) j++;
if( a[i].value < a[j].value ) break;
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
i = j;
}
}
/*
** Extract the first element from the queue (the element with
** the smallest value) and return its ID. Return 0 if the queue
** is empty.
*/
int pqueuex_extract(PQueue *p){
int e;
if( p->cnt==0 ){
return 0;
}
e = p->a[0].u.id;
pqueuex_pop(p);
return e;
}
void *pqueuex_extract_ptr(PQueue *p){
void *pPtr;
if( p->cnt==0 ){
return 0;
}
pPtr = p->a[0].u.p;
pqueuex_pop(p);
return pPtr;
}
/*
** Print the entire heap associated with the test-pqueue command.
*/
static void pqueuex_test_print(PQueue *p){
int j;
for(j=0; j<p->cnt; j++){
fossil_print("(%d) %g/%s ",j,p->a[j].value,p->a[j].u.p);
}
fossil_print("\n");
}
/*
** COMMAND: test-pqueue
**
** This command is used for testing the PQueue object. There are one
** or more arguments, each of the form:
**
** (1) NUMBER/TEXT
** (2) ^
** (3) -v
**
** Form (1) arguments add an entry to the queue with value NUMBER and
** content TEXT. Form (2) pops off the queue entry with the smallest
** value. Form (3) (the -v option) causes the heap to be displayed after
** each subsequent operation.
*/
void pqueuex_test_cmd(void){
int i;
PQueue x;
const char *zId;
int bDebug = 0;
pqueuex_init(&x);
for(i=2; i<g.argc; i++){
const char *zArg = g.argv[i];
if( strcmp(zArg,"-v")==0 ){
bDebug = 1;
}else if( strcmp(zArg, "^")==0 ){
zId = pqueuex_extract_ptr(&x);
if( zId==0 ){
fossil_print("%2d: POP NULL\n", i);
}else{
fossil_print("%2d: POP \"%s\"\n", i, zId);
}
if( bDebug) pqueuex_test_print(&x);
}else{
double r = atof(zArg);
zId = strchr(zArg,'/');
if( zId==0 ) zId = zArg;
if( zId[0]=='/' ) zId++;
pqueuex_insert_ptr(&x, (void*)zId, r);
fossil_print("%2d: INSERT \"%s\"\n", i, zId);
if( bDebug) pqueuex_test_print(&x);
}
}
while( (zId = pqueuex_extract_ptr(&x))!=0 ){
fossil_print("... POP \"%s\"\n", zId);
if( bDebug) pqueuex_test_print(&x);
}
pqueuex_clear(&x);
}
|
Changes to src/printf.c.
| ︙ | ︙ | |||
238 239 240 241 242 243 244 245 246 247 248 249 250 |
static int StrNLen32(const char *z, int N){
int n = 0;
while( (N-- != 0) && *(z++)!=0 ){ n++; }
return n;
}
#endif
/*
** Return an appropriate set of flags for wiki_convert() for displaying
** comments on a timeline. These flag settings are determined by
** configuration parameters.
**
** The altForm2 argument is true for "%!W" (with the "!" alternate-form-2
| > > > > > > > > > > > > > > > > > | > | < > > | > < | < < < | 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
static int StrNLen32(const char *z, int N){
int n = 0;
while( (N-- != 0) && *(z++)!=0 ){ n++; }
return n;
}
#endif
/*
** SETTING: timeline-plaintext boolean default=off
**
** If enabled, no wiki-formatting is done for timeline comment messages.
** Hyperlinks are activated, but they show up on screen using the
** complete input text, not just the display text. No other formatting
** is done.
*/
/*
** SETTING: timeline-hard-newlines boolean default=off
**
** If enabled, the timeline honors newline characters in check-in comments.
** In other words, newlines are coverted into <br> for HTML display.
** The default behavior, when this setting is off, is that newlines are
** treated like any other whitespace character.
*/
/*
** Return an appropriate set of flags for wiki_convert() for displaying
** comments on a timeline. These flag settings are determined by
** configuration parameters.
**
** The altForm2 argument is true for "%!W" (with the "!" alternate-form-2
** flags) and is false for plain "%W". The ! flag indicates that the
** formatting is for display of a check-in comment on the timeline. Such
** comments used to be renderedd differently, but ever since 2020, they
** have been rendered identially, so the ! flag does not make any different
** in the output any more.
*/
int wiki_convert_flags(int altForm2){
static int wikiFlags = 0;
(void)altForm2;
if( wikiFlags==0 ){
wikiFlags = WIKI_INLINE | WIKI_NOBADLINKS;
if( db_get_boolean("timeline-plaintext", 0) ){
wikiFlags |= WIKI_LINKSONLY;
}
if( db_get_boolean("timeline-hard-newlines", 0) ){
wikiFlags |= WIKI_NEWLINE;
}
}
|
| ︙ | ︙ |
Changes to src/rebuild.c.
| ︙ | ︙ | |||
1412 1413 1414 1415 1416 1417 1418 |
zPassword);
hash_user_password(g.zLogin);
}
/*
** COMMAND: deconstruct*
**
| | | 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 |
zPassword);
hash_user_password(g.zLogin);
}
/*
** COMMAND: deconstruct*
**
** Usage: %fossil deconstruct ?OPTIONS? DESTINATION
**
** This command exports all artifacts of a given repository and writes all
** artifacts to the file system. The DESTINATION directory will be populated
** with subdirectories AA and files AA/BBBBBBBBB.., where AABBBBBBBBB.. is the
** 40+ character artifact ID, AA the first 2 characters.
** If -L|--prefixlength is given, the length (default 2) of the directory prefix
** can be set to 0,1,..,9 characters.
|
| ︙ | ︙ |
Changes to src/regexp.c.
| ︙ | ︙ | |||
680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
}
}
if( j>0 && pRe->zInit[j-1]==0 ) j--;
pRe->nInit = j;
}
return pRe->zErr;
}
/*
** Implementation of the regexp() SQL function. This function implements
** the build-in REGEXP operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A REGEXP B
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 |
}
}
if( j>0 && pRe->zInit[j-1]==0 ) j--;
pRe->nInit = j;
}
return pRe->zErr;
}
/*
** The input zIn is a string that we want to match exactly as part of
** a regular expression. Return a new string (in space obtained from
** fossil_malloc() or the equivalent) that escapes all regexp syntax
** characters in zIn.
*/
char *re_quote(const char *zIn){
Blob out;
blob_init(&out, 0, 0);
while( zIn[0] ){
switch( zIn[0] ){
case '.':
case '?':
case '*':
case '+':
case '\\':
case '(':
case ')':
case '[':
case ']':
case '|':
case '^':
case '$':
case '{':
case '}': {
blob_appendf(&out,"\\x%02x", (unsigned char)zIn[0]);
break;
}
default: {
blob_append_char(&out, zIn[0]);
break;
}
}
zIn++;
}
blob_materialize(&out);
return out.aData;
}
/*
** Implementation of the regexp() SQL function. This function implements
** the build-in REGEXP operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A REGEXP B
|
| ︙ | ︙ |
Changes to src/repolist.c.
| ︙ | ︙ | |||
314 315 316 317 318 319 320 321 322 323 324 325 326 |
login_check_credentials();
style_set_current_feature("repolist");
style_header("Repository List");
@ %s(blob_str(&html))
style_table_sorter();
style_finish_page();
}else{
/* If no repositories were found that had the "repolist_skin"
** property set, then use a default skin */
@ <html>
@ <head>
@ <base href="%s(g.zBaseURL)/">
@ <meta name="viewport" content="width=device-width, initial-scale=1.0">
| > | | | 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
login_check_credentials();
style_set_current_feature("repolist");
style_header("Repository List");
@ %s(blob_str(&html))
style_table_sorter();
style_finish_page();
}else{
const char *zTitle = PD("FOSSIL_REPOLIST_TITLE","Repository List");
/* If no repositories were found that had the "repolist_skin"
** property set, then use a default skin */
@ <html>
@ <head>
@ <base href="%s(g.zBaseURL)/">
@ <meta name="viewport" content="width=device-width, initial-scale=1.0">
@ <title>%h(zTitle)</title>
@ </head>
@ <body>
@ <h1 align="center">%h(zTitle)</h1>
@ %s(blob_str(&html))
@ <script>%s(builtin_text("sorttable.js"))</script>
@ </body>
@ </html>
}
blob_reset(&html);
cgi_reply();
|
| ︙ | ︙ |
Changes to src/schema.c.
| ︙ | ︙ | |||
509 510 511 512 513 514 515 | /* ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ | | | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | /* ** Predefined tagid values */ #if INTERFACE # define TAG_BGCOLOR 1 /* Set the background color for display */ # define TAG_COMMENT 2 /* The check-in comment */ # define TAG_USER 3 /* User who made a check-in */ # define TAG_DATE 4 /* The date of a check-in */ # define TAG_HIDDEN 5 /* Do not display in timeline */ # define TAG_PRIVATE 6 /* Do not sync */ # define TAG_CLUSTER 7 /* A cluster */ # define TAG_BRANCH 8 /* Value is name of the current branch */ # define TAG_CLOSED 9 /* Do not display this check-in as a leaf */ # define TAG_PARENT 10 /* Change to parentage on a check-in */ |
| ︙ | ︙ |
Changes to src/search.c.
| ︙ | ︙ | |||
562 563 564 565 566 567 568 | } /* ** Testing the search function. ** ** COMMAND: search* ** | | | | | < | | > > > > > > | > > | < < < > > | | | | > > > | | | > > > > < | > > > > > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < > > > | > | | < | < < > | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
}
/*
** Testing the search function.
**
** COMMAND: search*
**
** Usage: %fossil search [OPTIONS] PATTERN...
**
** Search the repository for PATTERN and show matches. Depending on
** options and how the administrator has search configured for the
** repository, the search can cover:
**
** * check-in comments (-c)
** * embedded documentation (--docs)
** * forum posts (--forum)
** * tickets (--tickets)
** * tech notes (--technotes)
** * wiki pages (--wiki)
** * built-in fossil help text (-h)
** * all of the above (-a)
**
** Use options below to select the scope of the search. The
** default is check-in comments only (-c).
**
** Output is colorized if writing to a TTY and if the NO_COLOR environment
** variable is not set. Use the "--highlight 0" option to disable colorization
** or use "--highlight 91" to force it on. Change the argument to --highlight
** to change the color.
**
** Options:
** -a|--all Search everything
** -c|--checkins Search checkin comments
** --docs Search embedded documentation
** --forum Search forum posts
** -h|--bi-help Search built-in help
** --highlight N Used VT100 color N for matching text. 0 means "off".
** -n|--limit N Limit output to N matches
** --technotes Search tech notes
** --tickets Search tickets
** -W|--width WIDTH Set display width to WIDTH columns, 0 for
** unlimited. Defaults to the terminal's width.
** --wiki Search wiki
*/
void search_cmd(void){
Blob pattern;
int i;
Blob sql = empty_blob;
Stmt q;
int iBest;
int srchFlags = 0;
int bFts = 1; /* Use FTS search by default now */
char fAll = NULL != find_option("all", "a", 0);
const char *zLimit = find_option("limit","n",1);
const char *zScope = 0;
const char *zWidth = find_option("width","W",1);
int bDebug = find_option("debug",0,0)!=0; /* Undocumented */
int nLimit = zLimit ? atoi(zLimit) : -1000;
int width;
int nTty = 0; /* VT100 highlight color for matching text */
const char *zHighlight = 0;
nTty = terminal_is_vt100();
/* Undocumented option to change highlight color */
zHighlight = find_option("highlight",0,1);
if( zHighlight ) nTty = atoi(zHighlight);
/* Undocumented option (legacy) */
zScope = find_option("scope",0,1);
if( find_option("fts",0,0)!=0 ) bFts = 1; /* Undocumented legacy */
if( find_option("legacy",0,0)!=0 ) bFts = 0; /* Undocumented */
if( zWidth ){
width = atoi(zWidth);
if( (width!=0) && (width<=20) ){
fossil_fatal("-W|--width value must be >20 or 0");
}
}else{
width = -1;
}
if( zScope ){
for(i=0; zScope[i]; i++){
switch( zScope[i] ){
case 'a': srchFlags = SRCH_ALL; break;
case 'c': srchFlags |= SRCH_CKIN; break;
case 'd': srchFlags |= SRCH_DOC; break;
case 'e': srchFlags |= SRCH_TECHNOTE; break;
case 'f': srchFlags |= SRCH_FORUM; break;
case 'h': srchFlags |= SRCH_HELP; break;
case 't': srchFlags |= SRCH_TKT; break;
case 'w': srchFlags |= SRCH_WIKI; break;
}
}
bFts = 1;
}
if( find_option("all","a",0) ){ srchFlags |= SRCH_ALL; bFts = 1; }
if( find_option("bi-help","h",0) ){ srchFlags |= SRCH_HELP; bFts = 1; }
if( find_option("checkins","c",0) ){ srchFlags |= SRCH_CKIN; bFts = 1; }
if( find_option("docs",0,0) ){ srchFlags |= SRCH_DOC; bFts = 1; }
if( find_option("forum",0,0) ){ srchFlags |= SRCH_FORUM; bFts = 1; }
if( find_option("technotes",0,0) ){ srchFlags |= SRCH_TECHNOTE; bFts = 1; }
if( find_option("tickets",0,0) ){ srchFlags |= SRCH_TKT; bFts = 1; }
if( find_option("wiki",0,0) ){ srchFlags |= SRCH_WIKI; bFts = 1; }
/* If no search objects are specified, default to "check-in comments" */
if( srchFlags==0 ) srchFlags = SRCH_CKIN;
db_find_and_open_repository(0, 0);
verify_all_options();
if( g.argc<3 ) return;
login_set_capabilities("s", 0);
if( search_restrict(srchFlags)==0 && (srchFlags & SRCH_HELP)==0 ){
const char *zC1 = 0, *zPlural = "s";
if( srchFlags & SRCH_TECHNOTE ){ zC1 = "technote"; }
if( srchFlags & SRCH_TKT ){ zC1 = "ticket"; }
if( srchFlags & SRCH_FORUM ){ zC1 = "forum"; zPlural = ""; }
if( srchFlags & SRCH_DOC ){ zC1 = "document"; }
if( srchFlags & SRCH_WIKI ){ zC1 = "wiki"; zPlural = ""; }
if( srchFlags & SRCH_CKIN ){ zC1 = "check-in"; }
fossil_print(
"Search of %s%s is disabled on this repository.\n"
"Enable using \"fossil fts-config enable %s\".\n",
zC1, zPlural, zC1
);
return;
}
blob_init(&pattern, g.argv[2], -1);
for(i=3; i<g.argc; i++){
blob_appendf(&pattern, " %s", g.argv[i]);
}
if( bFts ){
/* Search using FTS */
Blob com;
Blob snip;
const char *zPattern = blob_str(&pattern);
search_sql_setup(g.db);
add_content_sql_commands(g.db);
db_multi_exec(
"CREATE TEMP TABLE x(label,url,score,id,date,snip);"
);
if( !search_index_exists() ){
search_fullscan(zPattern, srchFlags); /* Full-scan search */
}else{
search_update_index(srchFlags); /* Update the index */
search_indexed(zPattern, srchFlags); /* Indexed search */
if( srchFlags & SRCH_HELP ){
search_fullscan(zPattern, SRCH_HELP);
}
}
db_prepare(&q, "SELECT snip, label, score, id, date"
" FROM x"
" ORDER BY score DESC, date DESC;");
blob_init(&com, 0, 0);
blob_init(&snip, 0, 0);
if( width<0 ) width = terminal_get_width(80);
while( db_step(&q)==SQLITE_ROW ){
const char *zSnippet = db_column_text(&q, 0);
const char *zLabel = db_column_text(&q, 1);
const char *zDate = db_column_text(&q, 4);
const char *zScore = db_column_text(&q, 2);
const char *zId = db_column_text(&q, 3);
char *zOrig;
blob_appendf(&snip, "%s", zSnippet);
zOrig = blob_materialize(&snip);
blob_init(&snip, 0, 0);
html_to_plaintext(zOrig, &snip, (nTty?HTOT_VT100:0)|HTOT_FLOW|HTOT_TRIM);
fossil_free(zOrig);
blob_appendf(&com, "%s\n%s\n%s", zLabel, blob_str(&snip), zDate);
if( bDebug ){
blob_appendf(&com," score: %s id: %s", zScore, zId);
}
comment_print(blob_str(&com), 0, 5, width,
COMMENT_PRINT_TRIM_CRLF |
COMMENT_PRINT_WORD_BREAK |
|
| ︙ | ︙ | |||
729 730 731 732 733 734 735 | /* What to search for */ #define SRCH_CKIN 0x0001 /* Search over check-in comments */ #define SRCH_DOC 0x0002 /* Search over embedded documents */ #define SRCH_TKT 0x0004 /* Search over tickets */ #define SRCH_WIKI 0x0008 /* Search over wiki */ #define SRCH_TECHNOTE 0x0010 /* Search over tech notes */ #define SRCH_FORUM 0x0020 /* Search over forum messages */ | > | > > > | | | | | > | 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 |
/* What to search for */
#define SRCH_CKIN 0x0001 /* Search over check-in comments */
#define SRCH_DOC 0x0002 /* Search over embedded documents */
#define SRCH_TKT 0x0004 /* Search over tickets */
#define SRCH_WIKI 0x0008 /* Search over wiki */
#define SRCH_TECHNOTE 0x0010 /* Search over tech notes */
#define SRCH_FORUM 0x0020 /* Search over forum messages */
#define SRCH_HELP 0x0040 /* Search built-in help (full-scan only) */
#define SRCH_ALL 0x007f /* Search over everything */
#endif
/*
** Remove bits from srchFlags which are disallowed by either the
** current server configuration or by user permissions. Return
** the revised search flags mask.
**
** If bFlex is true, that means allow through the SRCH_HELP option
** even if it is not explicitly enabled.
*/
unsigned int search_restrict(unsigned int srchFlags){
static unsigned int knownGood = 0;
static unsigned int knownBad = 0;
static const struct { unsigned m; const char *zKey; } aSetng[] = {
{ SRCH_CKIN, "search-ci" },
{ SRCH_DOC, "search-doc" },
{ SRCH_TKT, "search-tkt" },
{ SRCH_WIKI, "search-wiki" },
{ SRCH_TECHNOTE, "search-technote" },
{ SRCH_FORUM, "search-forum" },
{ SRCH_HELP, "search-help" },
};
int i;
if( g.perm.Read==0 ) srchFlags &= ~(SRCH_CKIN|SRCH_DOC|SRCH_TECHNOTE);
if( g.perm.RdTkt==0 ) srchFlags &= ~(SRCH_TKT);
if( g.perm.RdWiki==0 ) srchFlags &= ~(SRCH_WIKI);
if( g.perm.RdForum==0) srchFlags &= ~(SRCH_FORUM);
for(i=0; i<count(aSetng); i++){
|
| ︙ | ︙ | |||
910 911 912 913 914 915 916 917 918 919 920 921 922 923 |
" 'f'||rid,"
" datetime(event.mtime),"
" search_snippet()"
" FROM event JOIN blob on event.objid=blob.rid"
" WHERE search_match('',body('f',rid,NULL));"
);
}
}
/*
** Number of significant bits in a u32
*/
static int nbits(u32 x){
int n = 0;
| > > > > > > > > > > > > > > > > > > > > > | 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
" 'f'||rid,"
" datetime(event.mtime),"
" search_snippet()"
" FROM event JOIN blob on event.objid=blob.rid"
" WHERE search_match('',body('f',rid,NULL));"
);
}
if( (srchFlags & SRCH_HELP)!=0 ){
const char *zPrefix;
helptext_vtab_register(g.db);
if( srchFlags==SRCH_HELP ){
zPrefix = "The";
}else{
zPrefix = "Built-in help for the";
}
db_multi_exec(
"INSERT INTO x(label,url,score,id,snip)"
" SELECT format('%q \"%%s\" %%s',name,type),"
" '/help?cmd='||name,"
" search_score(),"
" 'h'||rowid,"
" search_snippet()"
" FROM helptext"
" WHERE search_match(format('the \"%%s\" %%s',name,type),"
" helptext.helptext);",
zPrefix
);
}
}
/*
** Number of significant bits in a u32
*/
static int nbits(u32 x){
int n = 0;
|
| ︙ | ︙ | |||
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 |
static const struct { unsigned m; char c; } aMask[] = {
{ SRCH_CKIN, 'c' },
{ SRCH_DOC, 'd' },
{ SRCH_TKT, 't' },
{ SRCH_WIKI, 'w' },
{ SRCH_TECHNOTE, 'e' },
{ SRCH_FORUM, 'f' },
};
int i;
for(i=0; i<count(aMask); i++){
if( srchFlags & aMask[i].m ){
blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
zSep = " OR ";
}
| > | 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 |
static const struct { unsigned m; char c; } aMask[] = {
{ SRCH_CKIN, 'c' },
{ SRCH_DOC, 'd' },
{ SRCH_TKT, 't' },
{ SRCH_WIKI, 'w' },
{ SRCH_TECHNOTE, 'e' },
{ SRCH_FORUM, 'f' },
{ SRCH_HELP, 'h' },
};
int i;
for(i=0; i<count(aMask); i++){
if( srchFlags & aMask[i].m ){
blob_appendf(&sql, "%sftsdocs.type='%c'", zSep, aMask[i].c);
zSep = " OR ";
}
|
| ︙ | ︙ | |||
1155 1156 1157 1158 1159 1160 1161 |
Stmt q;
int nRow = 0;
int nLimit = db_get_int("search-limit", 100);
if( P("searchlimit")!=0 ){
nLimit = atoi(P("searchlimit"));
}
| | > > > | 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 |
Stmt q;
int nRow = 0;
int nLimit = db_get_int("search-limit", 100);
if( P("searchlimit")!=0 ){
nLimit = atoi(P("searchlimit"));
}
srchFlags = search_restrict(srchFlags) | (srchFlags & SRCH_HELP);
if( srchFlags==0 ) return 0;
search_sql_setup(g.db);
add_content_sql_commands(g.db);
db_multi_exec(
"CREATE TEMP TABLE x(label,url,score,id,date,snip);"
);
if( !search_index_exists() ){
search_fullscan(zPattern, srchFlags); /* Full-scan search */
}else{
search_update_index(srchFlags); /* Update the index, if necessary */
search_indexed(zPattern, srchFlags); /* Indexed search */
if( srchFlags & SRCH_HELP ){
search_fullscan(zPattern, SRCH_HELP);
}
}
db_prepare(&q, "SELECT url, snip, label, score, id, substr(date,1,10)"
" FROM x"
" ORDER BY score DESC, date DESC;");
while( db_step(&q)==SQLITE_ROW ){
const char *zUrl = db_column_text(&q, 0);
const char *zSnippet = db_column_text(&q, 1);
|
| ︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 | ** 0x01 If the y= query parameter is present, use it as an addition ** restriction what to search. ** ** 0x02 Show nothing if search is disabled. ** ** Return true if there are search results. */ | | > > > > > | > | > | > | | > > > > > < < | > > | < | | | | | | | | > | | 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 |
** 0x01 If the y= query parameter is present, use it as an addition
** restriction what to search.
**
** 0x02 Show nothing if search is disabled.
**
** Return true if there are search results.
*/
int search_screen(unsigned srchAllowed, int mFlags){
const char *zType = 0;
const char *zClass = 0;
const char *zDisable1;
const char *zDisable2;
const char *zPattern;
int fDebug = PB("debug");
int haveResult = 0;
int srchThisTime;
const char *zY = PD("y","all");
if( zY[0]=='h' && zY[1]==0 ){
srchAllowed = search_restrict(srchAllowed) | (srchAllowed & SRCH_HELP);
}else{
srchAllowed = search_restrict(srchAllowed);
}
switch( srchAllowed ){
case SRCH_CKIN: zType = " Check-ins"; zClass = "Ckin"; break;
case SRCH_DOC: zType = " Docs"; zClass = "Doc"; break;
case SRCH_TKT: zType = " Tickets"; zClass = "Tkt"; break;
case SRCH_WIKI: zType = " Wiki"; zClass = "Wiki"; break;
case SRCH_TECHNOTE: zType = " Tech Notes"; zClass = "Note"; break;
case SRCH_FORUM: zType = " Forum"; zClass = "Frm"; break;
case SRCH_HELP: zType = " Help"; zClass = "Hlp"; break;
}
if( srchAllowed==0 ){
if( mFlags & 0x02 ) return 0;
zDisable1 = " disabled";
zDisable2 = " disabled";
zPattern = "";
}else{
zDisable1 = ""; /* Was: " autofocus" */
zDisable2 = "";
zPattern = PD("s","");
}
@ <form method='GET' action='%R/%T(g.zPath)'>
if( zClass ){
@ <div class='searchForm searchForm%s(zClass)'>
}else{
@ <div class='searchForm'>
}
@ <input type="text" name="s" size="40" value="%h(zPattern)"%s(zDisable1)>
srchThisTime = srchAllowed;
if( (mFlags & 0x01)!=0 && (srchAllowed & (srchAllowed-1))!=0 ){
static const struct {
const char *z;
const char *zNm;
unsigned m;
} aY[] = {
{ "all", "All", SRCH_ALL },
{ "c", "Check-ins", SRCH_CKIN },
{ "d", "Docs", SRCH_DOC },
{ "t", "Tickets", SRCH_TKT },
{ "w", "Wiki", SRCH_WIKI },
{ "e", "Tech Notes", SRCH_TECHNOTE },
{ "f", "Forum", SRCH_FORUM },
{ "h", "Help", SRCH_HELP },
};
int i;
@ <select size='1' name='y'>
for(i=0; i<count(aY); i++){
if( (aY[i].m & srchAllowed)==0 ) continue;
if( aY[i].m==SRCH_HELP && fossil_strcmp(zY,"h")!=0
&& search_restrict(SRCH_HELP)==0 ) continue;
cgi_printf("<option value='%s'", aY[i].z);
if( fossil_strcmp(zY,aY[i].z)==0 ){
srchThisTime &= aY[i].m;
cgi_printf(" selected");
}
cgi_printf(">%s</option>\n", aY[i].zNm);
}
@ </select>
}
if( fDebug ){
@ <input type="hidden" name="debug" value="1">
}
@ <input type="submit" value="Search%s(zType)"%s(zDisable2)>
if( srchAllowed==0 && srchThisTime==0 ){
@ <p class="generalError">Search is disabled</p>
}
@ </div></form>
while( fossil_isspace(zPattern[0]) ) zPattern++;
if( zPattern[0] ){
if( zClass ){
@ <div class='searchResult searchResult%s(zClass)'>
}else{
@ <div class='searchResult'>
}
if( search_run_and_output(zPattern, srchThisTime, fDebug)==0 ){
@ <p class='searchEmpty'>No matches for: <span>%h(zPattern)</span></p>
}
@ </div>
haveResult = 1;
}
return haveResult;
}
/*
** WEBPAGE: search
**
** Search for check-in comments, documents, tickets, or wiki that
** match a user-supplied pattern.
**
** s=PATTERN Specify the full-text pattern to search for
** y=TYPE What to search.
** c -> check-ins,
** d -> documentation,
** t -> tickets,
** w -> wiki,
** e -> tech notes,
** f -> forum,
** h -> built-in help,
** all -> everything.
*/
void search_page(void){
const int isSearch = P("s")!=0;
login_check_credentials();
style_header("Search%s", isSearch ? " Results" : "");
cgi_check_for_malice();
search_screen(SRCH_ALL, 1);
|
| ︙ | ︙ | |||
1372 1373 1374 1375 1376 1377 1378 |
wiki_convert(&tail, &html, 0);
blob_reset(&tail);
}else{
blob_append(pOut, "\n", 1);
wiki_convert(pIn, &html, 0);
}
}
| | | | 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 |
wiki_convert(&tail, &html, 0);
blob_reset(&tail);
}else{
blob_append(pOut, "\n", 1);
wiki_convert(pIn, &html, 0);
}
}
html_to_plaintext(blob_str(&html), pOut, 0);
}else if( fossil_strcmp(zMimetype,"text/x-markdown")==0 ){
markdown_to_html(pIn, blob_size(&title) ? NULL : &title, &html);
}else if( fossil_strcmp(zMimetype,"text/html")==0 ){
if( blob_size(&title)==0 ) doc_is_embedded_html(pIn, &title);
pHtml = pIn;
}
blob_appendf(pOut, "%s\n", blob_str(&title));
if( blob_size(pHtml) ){
html_to_plaintext(blob_str(pHtml), pOut, 0);
}else{
blob_append(pOut, blob_buffer(pIn), blob_size(pIn));
}
blob_reset(&html);
blob_reset(&title);
}
|
| ︙ | ︙ | |||
2106 2107 2108 2109 2110 2111 2112 |
if( db_table_exists("repository","chat") ){
chat_rebuild_index(1);
}
fossil_print(" done\n");
}
/*
| | | | | | | | | | | | | | | | | | | > | 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 |
if( db_table_exists("repository","chat") ){
chat_rebuild_index(1);
}
fossil_print(" done\n");
}
/*
** COMMAND: fts-config* abbrv-subcom
**
** Usage: fossil fts-config ?SUBCOMMAND? ?ARGUMENT?
**
** The "fossil fts-config" command configures the full-text search capabilities
** of the repository. Subcommands:
**
** reindex Rebuild the search index. This is a no-op if
** index search is disabled
**
** index (on|off) Turn the search index on or off
**
** enable TYPE .. Enable search for TYPE. TYPE is one of:
** check-in, document, ticket, wiki, technote,
** forum, help, or all
**
** disable TYPE ... Disable search for TYPE
**
** tokenizer VALUE Select a tokenizer for indexed search. VALUE
** may be one of (porter, on, off, trigram, unicode61),
** and "on" is equivalent to "porter". Unindexed
** search never uses tokenization or stemming.
**
** The current search settings are displayed after any changes are applied.
** Run this command with no arguments to simply see the settings.
*/
void fts_config_cmd(void){
static const struct {
int iCmd;
const char *z;
} aCmd[] = {
{ 1, "reindex" },
{ 2, "index" },
{ 3, "disable" },
{ 4, "enable" },
{ 5, "tokenizer"},
};
static const struct {
const char *zSetting;
const char *zName;
const char *zSw;
} aSetng[] = {
{ "search-ci", "check-in search:", "c" },
{ "search-doc", "document search:", "d" },
{ "search-tkt", "ticket search:", "t" },
{ "search-wiki", "wiki search:", "w" },
{ "search-technote", "technote search:", "e" },
{ "search-forum", "forum search:", "f" },
{ "search-help", "built-in help search:", "h" },
};
char *zSubCmd = 0;
int i, j, n;
int iCmd = 0;
int iAction = 0;
db_find_and_open_repository(0, 0);
if( g.argc>2 ){
|
| ︙ | ︙ | |||
2190 2191 2192 2193 2194 2195 2196 2197 |
if( g.argc<3 ) usage("index (on|off)");
iAction = 1 + is_truth(g.argv[3]);
}
db_begin_transaction();
/* Adjust search settings */
if( iCmd==3 || iCmd==4 ){
const char *zCtrl;
| > > > | > > | > > > > > > > > > > > > > | > > > > > > > > > > | | > > | 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 |
if( g.argc<3 ) usage("index (on|off)");
iAction = 1 + is_truth(g.argv[3]);
}
db_begin_transaction();
/* Adjust search settings */
if( iCmd==3 || iCmd==4 ){
int k;
const char *zCtrl;
for(k=2; k<g.argc; k++){
if( k==2 ){
if( g.argc<4 ){
zCtrl = "all";
}else{
zCtrl = g.argv[3];
k++;
}
}else{
zCtrl = g.argv[k];
}
if( fossil_strcmp(zCtrl,"all")==0 ){
zCtrl = "cdtwefh";
}
if( strlen(zCtrl)>=4 ){
/* If the argument to "enable" or "disable" is a string of at least
** 4 characters which matches part of any aSetng.zName, then use that
** one aSetng value only. */
char *zGlob = mprintf("*%s*", zCtrl);
for(j=0; j<count(aSetng); j++){
if( sqlite3_strglob(zGlob, aSetng[j].zName)==0 ){
db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
zCtrl = 0;
break;
}
}
fossil_free(zGlob);
}
if( zCtrl ){
for(j=0; j<count(aSetng); j++){
if( strchr(zCtrl, aSetng[j].zSw[0])!=0 ){
db_set_int(aSetng[j].zSetting/*works-like:"x"*/, iCmd-3, 0);
}
}
}
}
}else if( iCmd==5 ){
int iOldTokenizer, iNewTokenizer;
if( g.argc<4 ) usage("tokenizer porter|on|off|trigram|unicode61");
iOldTokenizer = search_tokenizer_type(0);
db_set("search-tokenizer",
|
| ︙ | ︙ | |||
2222 2223 2224 2225 2226 2227 2228 |
}
if( iAction>=2 ){
search_rebuild_index();
}
/* Always show the status before ending */
for(i=0; i<count(aSetng); i++){
| | | | | | | | 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 |
}
if( iAction>=2 ){
search_rebuild_index();
}
/* Always show the status before ending */
for(i=0; i<count(aSetng); i++){
fossil_print("%-21s %s\n", aSetng[i].zName,
db_get_boolean(aSetng[i].zSetting,0) ? "on" : "off");
}
fossil_print("%-21s %s\n", "tokenizer:",
search_tokenizer_for_string(0));
if( search_index_exists() ){
int pgsz = db_int64(0, "PRAGMA repository.page_size;");
i64 nTotal = db_int64(0, "PRAGMA repository.page_count;")*pgsz;
i64 nFts = db_int64(0, "SELECT count(*) FROM dbstat"
" WHERE schema='repository'"
" AND name LIKE 'fts%%'")*pgsz;
char zSize[50];
fossil_print("%-21s FTS%d\n", "full-text index:", search_index_type(1));
fossil_print("%-21s %d\n", "documents:",
db_int(0, "SELECT count(*) FROM ftsdocs"));
approxSizeName(sizeof(zSize), zSize, nFts);
fossil_print("%-21s %s (%.1f%% of repository)\n", "space used",
zSize, 100.0*((double)nFts/(double)nTotal));
}else{
fossil_print("%-21s disabled\n", "full-text index:");
}
db_end_transaction(0);
}
/*
** WEBPAGE: test-ftsdocs
**
|
| ︙ | ︙ |
Changes to src/security_audit.c.
| ︙ | ︙ | |||
551 552 553 554 555 556 557 |
@ Fossil's built-in authentication mechanism is bypassed.
@ Fix this by deactivating the "Allow HTTP_AUTHENTICATION authentication"
@ checkbox on the <a href="setup_access">Access Control</a> page.
}
/* Logging should be turned on
*/
| | | | 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
@ Fossil's built-in authentication mechanism is bypassed.
@ Fix this by deactivating the "Allow HTTP_AUTHENTICATION authentication"
@ checkbox on the <a href="setup_access">Access Control</a> page.
}
/* Logging should be turned on
*/
if( db_get_boolean("access-log",1)==0 ){
@ <li><p>
@ The <a href="access_log">User Log</a> is disabled. The user log
@ keeps a record of successful and unsuccessful login attempts and is
@ useful for security monitoring.
}
if( db_get_boolean("admin-log",1)==0 ){
@ <li><p>
@ The <a href="admin_log">Administrative Log</a> is disabled.
@ The administrative log provides a record of configuration changes
@ and is useful for security monitoring.
}
#if !defined(_WIN32) && !defined(FOSSIL_OMIT_LOAD_AVERAGE)
|
| ︙ | ︙ | |||
802 803 804 805 806 807 808 |
@ <blockquote><pre>
@ errorlog: <i>FILENAME</i>
@ </pre></blockquote>
blob_reset(&fullname);
}
}
| < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > | < > | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 |
@ <blockquote><pre>
@ errorlog: <i>FILENAME</i>
@ </pre></blockquote>
blob_reset(&fullname);
}
}
/*
** WEBPAGE: errorlog
**
** Show the content of the error log. Only the administrator can view
** this page.
**
** y=0x01 Show only hack attempts
** y=0x02 Show only panics and assertion faults
** y=0x04 Show hung backoffice processes
** y=0x08 Show POST requests from a different origin
** y=0x40 Show other uncategorized messages
**
** If y is omitted or is zero, a count of the various message types is
** shown.
*/
void errorlog_page(void){
i64 szFile;
FILE *in;
char *zLog;
const char *zType = P("y");
static const int eAllTypes = 0x4f;
long eType = 0;
int bOutput = 0;
int prevWasTime = 0;
int nHack = 0;
int nPanic = 0;
int nOther = 0;
int nHang = 0;
int nXPost = 0;
char z[10000];
char zTime[10000];
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
if( zType ){
eType = strtol(zType,0,0) & eAllTypes;
}
style_header("Server Error Log");
style_submenu_element("Test", "%R/test-warning");
style_submenu_element("Refresh", "%R/errorlog");
style_submenu_element("Download", "%R/errorlog?download");
style_submenu_element("Truncate", "%R/errorlog?truncate");
style_submenu_element("Log-Menu", "%R/setup-logmenu");
if( eType ){
style_submenu_element("Summary", "%R/errorlog");
}
if( g.zErrlog==0 || fossil_strcmp(g.zErrlog,"-")==0 ){
no_error_log_available();
style_finish_page();
return;
}
if( P("truncate1") && cgi_csrf_safe(2) ){
|
| ︙ | ︙ | |||
859 860 861 862 863 864 865 |
@ </form>
style_finish_page();
return;
}
zLog = file_canonical_name_dup(g.zErrlog);
@ <p>The server error log at "%h(zLog)" is %,lld(szFile) bytes in size.
fossil_free(zLog);
| < < | | > | < | | > | < | < | | < > | < | > > | < < < < > | > | < < < < < < < < | > > < < < < < < < | < < < < < < < < < < < < < < < < < < | > > > > | > > > > > > > > > > > > > > > | | < > | > | < | | < < < < < < < < < < < | | < < < | < | < < > > | | < > > | < < < | > > | < | < | | | < < < < < < | | < > > | > | < < < > | < < < < > < > < | | < < < | 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 |
@ </form>
style_finish_page();
return;
}
zLog = file_canonical_name_dup(g.zErrlog);
@ <p>The server error log at "%h(zLog)" is %,lld(szFile) bytes in size.
fossil_free(zLog);
in = fossil_fopen(g.zErrlog, "rb");
if( in==0 ){
@ <p class='generalError'>Unable to open that file for reading!</p>
style_finish_page();
return;
}
if( eType==0 ){
/* will do a summary */
}else if( (eType&eAllTypes)!=eAllTypes ){
@ Only the following types of messages displayed:
@ <ul>
if( eType & 0x01 ){
@ <li>Hack attempts
}
if( eType & 0x02 ){
@ <li>Panics and assertion faults
}
if( eType & 0x04 ){
@ <li>Hung backoffice processes
}
if( eType & 0x08 ){
@ <li>POST requests from different origin
}
if( eType & 0x40 ){
@ <li>Other uncategorized messages
}
@ </ul>
}
@ <hr>
if( eType ){
@ <pre>
}
while( fgets(z, sizeof(z), in) ){
if( prevWasTime ){
if( strncmp(z,"possible hack attempt - 418 ", 27)==0 ){
bOutput = (eType & 0x01)!=0;
nHack++;
}else
if( (strncmp(z,"panic: ", 7)==0 || strstr(z," assertion fault ")!=0) ){
bOutput = (eType & 0x02)!=0;
nPanic++;
}else
if( sqlite3_strglob("warning: backoffice process * still *",z)==0 ){
bOutput = (eType & 0x04)!=0;
nHang++;
}else
if( sqlite3_strglob("warning: POST from different origin*",z)==0 ){
bOutput = (eType & 0x08)!=0;
nXPost++;
}else
{
bOutput = (eType & 0x40)!=0;
nOther++;
}
if( bOutput ){
@ %h(zTime)\
}
}
if( strncmp(z, "--------", 8)==0 ){
size_t n = strlen(z);
memcpy(zTime, z, n+1);
prevWasTime = 1;
bOutput = 0;
}else{
prevWasTime = 0;
}
if( bOutput && eType ){
@ %h(z)\
}
}
fclose(in);
if( eType ){
@ </pre>
}
if( eType==0 ){
int nNonHack = nPanic + nHang + nOther;
int nTotal = nNonHack + nHack + nXPost;
@ <p><table border="a" cellspacing="0" cellpadding="5">
if( nPanic>0 ){
@ <tr><td align="right">%d(nPanic)</td>
@ <td><a href="./errorlog?y=2">Panics</a></td>
}
if( nHack>0 ){
@ <tr><td align="right">%d(nHack)</td>
@ <td><a href="./errorlog?y=1">Hack Attempts</a></td>
}
if( nHang>0 ){
@ <tr><td align="right">%d(nHang)</td>
@ <td><a href="./errorlog?y=4/">Hung Backoffice</a></td>
}
if( nXPost>0 ){
@ <tr><td align="right">%d(nXPost)</td>
@ <td><a href="./errorlog?y=8/">POSTs from different origin</a></td>
}
if( nOther>0 ){
@ <tr><td align="right">%d(nOther)</td>
@ <td><a href="./errorlog?y=64/">Other</a></td>
}
if( nHack+nXPost>0 && nNonHack>0 ){
@ <tr><td align="right">%d(nNonHack)</td>
@ <td><a href="%R/errorlog?y=70">Other than hack attempts</a></td>
}
@ <tr><td align="right">%d(nTotal)</td>
if( nTotal>0 ){
@ <td><a href="./errorlog?y=255">All Messages</a></td>
}else{
@ <td>All Messages</td>
}
@ </table>
}
style_finish_page();
}
|
Changes to src/setup.c.
| ︙ | ︙ | |||
181 182 183 184 185 186 187 | style_finish_page(); } /* ** WEBPAGE: setup-logmenu ** | | | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
style_finish_page();
}
/*
** WEBPAGE: setup-logmenu
**
** Show a menu of available log renderings accessible to an administrator,
** together with a succinct explanation of each.
**
** This page is only accessible by administrators.
*/
void setup_logmenu_page(void){
Blob desc;
int bErrLog; /* True if Error Log enabled */
blob_init(&desc, 0, 0);
/* Administrator access only */
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
return;
}
style_header("Log Menu");
@ <table border="0" cellspacing="3">
if( db_get_boolean("admin-log",1)==0 ){
blob_appendf(&desc,
"The admin log records configuration changes to the repository.\n"
"<b>Disabled</b>: Turn on the "
" <a href='%R/setup_settings'>admin-log setting</a> to enable."
);
setup_menu_entry("Admin Log", 0, blob_str(&desc));
blob_reset(&desc);
}else{
setup_menu_entry("Admin Log", "admin_log",
"The admin log records configuration changes to the repository\n"
"in the \"admin_log\" table.\n"
);
}
setup_menu_entry("Artifact Log", "rcvfromlist",
"The artifact log records when new content is added in the\n"
"\"rcvfrom\" table.\n"
);
if( db_get_boolean("access-log",1) ){
setup_menu_entry("User Log", "user_log",
"Login attempts recorded in the \"accesslog\" table."
);
}else{
blob_appendf(&desc,
"Login attempts recorded in the \"accesslog\" table.\n"
"<b>Disabled</b>: Turn on the "
|
| ︙ | ︙ | |||
262 263 264 265 266 267 268 |
blob_appendf(&desc,"In this repository, the error log is the file "
"named \"%s\".", g.zErrlog);
bErrLog = 1;
}
setup_menu_entry("Error Log", bErrLog ? "errorlog" : 0, blob_str(&desc));
blob_reset(&desc);
| < < < < < < < < < < < < < < < < < | 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
blob_appendf(&desc,"In this repository, the error log is the file "
"named \"%s\".", g.zErrlog);
bErrLog = 1;
}
setup_menu_entry("Error Log", bErrLog ? "errorlog" : 0, blob_str(&desc));
blob_reset(&desc);
@ </table>
style_finish_page();
}
/*
** Generate a checkbox for an attribute.
*/
|
| ︙ | ︙ | |||
950 951 952 953 954 955 956 | @ <li><p><b>project-description</b> → @ A description of project in this repository. This is a verbose form @ of project-name. This description can be edited in the second entry @ box on the <a href="./setup_config">Setup/Configuration page</a>. @ @ <li><p><b>project-name</b> → @ The human-readable name for the project. The project-name can be | | | 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 | @ <li><p><b>project-description</b> → @ A description of project in this repository. This is a verbose form @ of project-name. This description can be edited in the second entry @ box on the <a href="./setup_config">Setup/Configuration page</a>. @ @ <li><p><b>project-name</b> → @ The human-readable name for the project. The project-name can be @ modified in the first entry on the @ <a href="./setup_config">Setup/Configuration page</a>. @ @ <li><p><b>peer-repo-<i>CODE</i></b> → @ <i>CODE</i> is 16-character prefix of the project-code for another @ repository that is part of the same login-group. The value is the @ filename for the peer repository. @ |
| ︙ | ︙ | |||
996 997 998 999 1000 1001 1002 |
style_set_current_feature("setup");
style_header("Timeline Display Preferences");
db_begin_transaction();
@ <form action="%R/setup_timeline" method="post"><div>
login_insert_csrf_secret();
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
| < < < < < < < | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 |
style_set_current_feature("setup");
style_header("Timeline Display Preferences");
db_begin_transaction();
@ <form action="%R/setup_timeline" method="post"><div>
login_insert_csrf_secret();
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
onoff_attribute("Plaintext comments on timelines",
"timeline-plaintext", "tpt", 0, 0);
@ <p>In timeline displays, check-in comments are displayed literally,
@ without any wiki or HTML interpretation. Use CSS to change
@ display formatting features such as fonts and line-wrapping behavior.
@ (Property: "timeline-plaintext")</p>
|
| ︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 |
** Change or view miscellaneous settings. Part of the
** /setup pages requiring Setup privileges.
*/
void setup_settings(void){
int nSetting;
int i;
Setting const *pSet;
const Setting *aSetting = setting_info(&nSetting);
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Settings");
if(!g.repositoryOpen){
/* Provide read-only access to versioned settings,
but only if no repo file was explicitly provided. */
db_open_local(0);
}
db_begin_transaction();
@ <p>Settings marked with (v) are "versionable" and will be overridden
@ by the contents of managed files named
@ "<tt>.fossil-settings/</tt><i>SETTING-NAME</i>".
@ If the file for a versionable setting exists, the value cannot be
@ changed on this screen.</p><hr><p>
@
@ <form action="%R/setup_settings" method="post"><div>
@ <table border="0"><tr><td valign="top">
login_insert_csrf_secret();
for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
if( pSet->width==0 ){
int hasVersionableValue = pSet->versionable &&
| > > > > > > > > > > > | > > > | > > > | > > > | 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 |
** Change or view miscellaneous settings. Part of the
** /setup pages requiring Setup privileges.
*/
void setup_settings(void){
int nSetting;
int i;
Setting const *pSet;
int bIfChng = P("all")==0;
const Setting *aSetting = setting_info(&nSetting);
login_check_credentials();
if( !g.perm.Setup ){
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("Settings");
if(!g.repositoryOpen){
/* Provide read-only access to versioned settings,
but only if no repo file was explicitly provided. */
db_open_local(0);
}
db_begin_transaction();
if( bIfChng ){
@ <p>Only settings whose value is different from the default are shown.
@ Click the "All" button above to set all settings.
}
@ <p>Settings marked with (v) are "versionable" and will be overridden
@ by the contents of managed files named
@ "<tt>.fossil-settings/</tt><i>SETTING-NAME</i>".
@ If the file for a versionable setting exists, the value cannot be
@ changed on this screen.</p><hr><p>
@
@ <form action="%R/setup_settings" method="post"><div>
if( bIfChng ){
style_submenu_element("All", "%R/setup_settings?all");
}else{
@ <input type="hidden" name="all" value="1">
style_submenu_element("Changes-Only", "%R/setup_settings");
}
@ <table border="0"><tr><td valign="top">
login_insert_csrf_secret();
for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
if( pSet->width==0 ){
int hasVersionableValue = pSet->versionable &&
(db_get_versioned(pSet->name, NULL, NULL)!=0);
if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
continue;
}
onoff_attribute("", pSet->name,
pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
is_truth(pSet->def), hasVersionableValue);
@ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
if( pSet->versionable ){
@ (v)<br>
} else {
@ <br>
}
}
}
@ <br><input type="submit" name="submit" value="Apply Changes">
@ </td><td style="width:50px;"></td><td valign="top">
@ <table>
for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
if( pSet->width>0 && !pSet->forceTextArea ){
int hasVersionableValue = pSet->versionable &&
(db_get_versioned(pSet->name, NULL, NULL)!=0);
if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
continue;
}
@ <tr><td>
@ <a href='%R/help?cmd=%s(pSet->name)'>%h(pSet->name)</a>
if( pSet->versionable ){
@ (v)
} else {
@
}
@</td><td>
entry_attribute("", /*pSet->width*/ 25, pSet->name,
pSet->var!=0 ? pSet->var : pSet->name /*works-like:"x"*/,
(char*)pSet->def, hasVersionableValue);
@</td></tr>
}
}
@</table>
@ </td><td style="width:50px;"></td><td valign="top">
for(i=0, pSet=aSetting; i<nSetting; i++, pSet++){
if( pSet->width>0 && pSet->forceTextArea ){
int hasVersionableValue = db_get_versioned(pSet->name, NULL, NULL)!=0;
if( bIfChng && setting_has_default_value(pSet, db_get(pSet->name,0)) ){
continue;
}
@ <a href='%R/help?cmd=%s(pSet->name)'>%s(pSet->name)</a>
if( pSet->versionable ){
@ (v)<br>
} else {
@ <br>
}
textarea_attribute("", /*rows*/ 2, /*cols*/ 35, pSet->name,
|
| ︙ | ︙ | |||
1426 1427 1428 1429 1430 1431 1432 |
style_set_current_feature("setup");
style_header("Wiki Configuration");
db_begin_transaction();
@ <form action="%R/setup_wiki" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
| | | | | | > | 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 |
style_set_current_feature("setup");
style_header("Wiki Configuration");
db_begin_transaction();
@ <form action="%R/setup_wiki" method="post"><div>
login_insert_csrf_secret();
@ <input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
onoff_attribute("Associate Wiki Pages With Branches, Tags, Tickets, or Checkins",
"wiki-about", "wiki-about", 1, 0);
@ <p>
@ Associate wiki pages with branches, tags, tickets, or checkins, based on
@ the wiki page name. Wiki pages that begin with "branch/", "checkin/",
@ "tag/" or "ticket" and which continue with the name of an existing branch,
@ check-in, tag or ticket are treated specially when this feature is enabled.
@ <ul>
@ <li> <b>branch/</b><i>branch-name</i>
@ <li> <b>checkin/</b><i>full-check-in-hash</i>
@ <li> <b>tag/</b><i>tag-name</i>
@ <li> <b>ticket/</b><i>full-ticket-hash</i>
@ </ul>
@ (Property: "wiki-about")</p>
@ <hr>
entry_attribute("Allow Unsafe HTML In Markdown", 6,
"safe-html", "safe-html", "", 0);
@ <p>Allow "unsafe" HTML (ex: <script>, <form>, etc) to be
@ generated by <a href="%R/md_rules">Markdown-formatted</a> documents.
|
| ︙ | ︙ | |||
2135 2136 2137 2138 2139 2140 2141 |
}
style_set_current_feature("setup");
style_header("Admin Log");
style_submenu_element("Log-Menu", "setup-logmenu");
create_admin_log_table();
limit = atoi(PD("n","200"));
ofst = atoi(PD("x","0"));
| | | 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 |
}
style_set_current_feature("setup");
style_header("Admin Log");
style_submenu_element("Log-Menu", "setup-logmenu");
create_admin_log_table();
limit = atoi(PD("n","200"));
ofst = atoi(PD("x","0"));
fLogEnabled = db_get_boolean("admin-log", 1);
@ <div>Admin logging is %s(fLogEnabled?"on":"off").
@ (Change this on the <a href="setup_settings">settings</a> page.)</div>
if( ofst>0 ){
int prevx = ofst - limit;
if( prevx<0 ) prevx = 0;
@ <p><a href="admin_log?n=%d(limit)&x=%d(prevx)">[Newer]</a></p>
|
| ︙ | ︙ | |||
2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 |
onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
@ <br>
onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
@ <br>
onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
@ <br>
onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
if( P("fts0") ){
search_drop_index();
}else if( P("fts1") ){
const char *zTokenizer = PD("ftstok","off");
| > > | 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 |
onoff_attribute("Search Tickets", "search-tkt", "st", 0, 0);
@ <br>
onoff_attribute("Search Wiki", "search-wiki", "sw", 0, 0);
@ <br>
onoff_attribute("Search Tech Notes", "search-technote", "se", 0, 0);
@ <br>
onoff_attribute("Search Forum", "search-forum", "sf", 0, 0);
@ <br>
onoff_attribute("Search Built-in Help Text", "search-help", "sh", 0, 0);
@ <hr>
@ <p><input type="submit" name="submit" value="Apply Changes"></p>
@ <hr>
if( P("fts0") ){
search_drop_index();
}else if( P("fts1") ){
const char *zTokenizer = PD("ftstok","off");
|
| ︙ | ︙ |
Changes to src/setupuser.c.
| ︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
*/
static int isValidPwString(const char *zPw){
if( zPw==0 ) return 0;
if( zPw[0]==0 ) return 1;
while( zPw[0]=='*' ){ zPw++; }
return zPw[0]!=0;
}
/*
** WEBPAGE: setup_uedit
**
** Edit information about a user or create a new user.
** Requires Admin privileges.
*/
void user_edit(void){
const char *zId, *zLogin, *zInfo, *zCap, *zPw;
const char *zGroup;
const char *zOldLogin;
int uid, i;
char *zDeleteVerify = 0; /* Delete user verification text */
int higherUser = 0; /* True if user being edited is SETUP and the */
/* user doing the editing is ADMIN. Disallow editing */
const char *inherit[128];
int a[128];
const char *oa[128];
/* Must have ADMIN privileges to access this page
*/
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
/* Check to see if an ADMIN user is trying to edit a SETUP account.
** Don't allow that.
*/
zId = PD("id", "0");
uid = atoi(zId);
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | > | > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
*/
static int isValidPwString(const char *zPw){
if( zPw==0 ) return 0;
if( zPw[0]==0 ) return 1;
while( zPw[0]=='*' ){ zPw++; }
return zPw[0]!=0;
}
/*
** Return true if user capability string zNew contains any capability
** letter which is not in user capability string zOrig, else 0. This
** does not take inherited permissions into account. Either argument
** may be NULL.
*/
static int userHasNewCaps(const char *zOrig, const char *zNew){
for( ; zNew && *zNew; ++zNew ){
if( !zOrig || strchr(zOrig,*zNew)==0 ){
return *zNew;
}
}
return 0;
}
/*
** Sends notification of user permission elevation changes to all
** subscribers with a "u" subscription. This is a no-op if alerts are
** not enabled.
**
** These subscriptions differ from most, in that:
**
** - They currently lack an "unsubscribe" link.
**
** - Only an admin can assign this subscription, but if a non-admin
** edits their subscriptions after an admin assigns them this one,
** this particular one will be lost. "Feature or bug?" is unclear,
** but it would be odd for a non-admin to be assigned this
** capability.
*/
static void alert_user_elevation(const char *zLogin, /*Affected user*/
int uid, /*[user].uid*/
int bIsNew, /*true if new user*/
const char *zOrigCaps,/*Old caps*/
const char *zNewCaps /*New caps*/){
Blob hdr, body;
Stmt q;
int nBody;
AlertSender *pSender;
char *zSubname;
char *zURL;
char * zSubject;
if( !alert_enabled() ) return;
zSubject = bIsNew
? mprintf("New user created: [%q]", zLogin)
: mprintf("User [%q] permissions elevated", zLogin);
zURL = db_get("email-url",0);
zSubname = db_get("email-subname", "[Fossil Repo]");
blob_init(&body, 0, 0);
blob_init(&hdr, 0, 0);
if( bIsNew ){
blob_appendf(&body, "User [%q] was created by with "
"permissions [%q] by user [%q].\n",
zLogin, zNewCaps, g.zLogin);
} else {
blob_appendf(&body, "Permissions for user [%q] where elevated "
"from [%q] to [%q] by user [%q].\n",
zLogin, zOrigCaps, zNewCaps, g.zLogin);
}
if( zURL ){
blob_appendf(&body, "\nUser editor: %s/setup_uedit?uid=%d\n", zURL, uid);
}
nBody = blob_size(&body);
pSender = alert_sender_new(0, 0);
db_prepare(&q,
"SELECT semail, hex(subscriberCode)"
" FROM subscriber, user "
" WHERE sverified AND NOT sdonotcall"
" AND suname=login"
" AND ssub GLOB '*u*'");
while( !pSender->zErr && db_step(&q)==SQLITE_ROW ){
const char *zTo = db_column_text(&q, 0);
blob_truncate(&hdr, 0);
blob_appendf(&hdr, "To: <%s>\r\nSubject: %s %s\r\n",
zTo, zSubname, zSubject);
if( zURL ){
const char *zCode = db_column_text(&q, 1);
blob_truncate(&body, nBody);
blob_appendf(&body,"\n-- \nSubscription info: %s/alerts/%s\n",
zURL, zCode);
}
alert_send(pSender, &hdr, &body, 0);
}
db_finalize(&q);
alert_sender_free(pSender);
fossil_free(zURL);
fossil_free(zSubname);
fossil_free(zSubject);
}
/*
** WEBPAGE: setup_uedit
**
** Edit information about a user or create a new user.
** Requires Admin privileges.
*/
void user_edit(void){
const char *zId, *zLogin, *zInfo, *zCap, *zPw;
const char *zGroup;
const char *zOldLogin;
int uid, i;
char *zOldCaps = 0; /* Capabilities before edit */
char *zDeleteVerify = 0; /* Delete user verification text */
int higherUser = 0; /* True if user being edited is SETUP and the */
/* user doing the editing is ADMIN. Disallow editing */
const char *inherit[128];
int a[128];
const char *oa[128];
/* Must have ADMIN privileges to access this page
*/
login_check_credentials();
if( !g.perm.Admin ){ login_needed(0); return; }
/* Check to see if an ADMIN user is trying to edit a SETUP account.
** Don't allow that.
*/
zId = PD("id", "0");
uid = atoi(zId);
if( uid>0 ){
zOldCaps = db_text("", "SELECT cap FROM user WHERE uid=%d",uid);
if( zId && !g.perm.Setup ){
higherUser = zOldCaps && strchr(zOldCaps,'s');
}
}
if( P("can") ){
/* User pressed the cancel button */
cgi_redirect(cgi_referer("setup_ulist"));
return;
}
|
| ︙ | ︙ | |||
391 392 393 394 395 396 397 |
}else if( zDeleteVerify!=0 ){
/* Need to verify a delete request */
}else if( !cgi_csrf_safe(2) ){
/* This might be a cross-site request forgery, so ignore it */
}else{
/* We have all the information we need to make the change to the user */
char c;
| > > | | | | | > | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 |
}else if( zDeleteVerify!=0 ){
/* Need to verify a delete request */
}else if( !cgi_csrf_safe(2) ){
/* This might be a cross-site request forgery, so ignore it */
}else{
/* We have all the information we need to make the change to the user */
char c;
int bHasNewCaps = 0 /* 1 if user's permissions are increased */;
const int bIsNew = uid<=0;
char aCap[70], zNm[4];
zNm[0] = 'a';
zNm[2] = 0;
for(i=0, c='a'; c<='z'; c++){
zNm[1] = c;
a[c&0x7f] = ((c!='s' && c!='y') || g.perm.Setup) && P(zNm)!=0;
if( a[c&0x7f] ) aCap[i++] = c;
}
for(c='0'; c<='9'; c++){
zNm[1] = c;
a[c&0x7f] = P(zNm)!=0;
if( a[c&0x7f] ) aCap[i++] = c;
}
for(c='A'; c<='Z'; c++){
zNm[1] = c;
a[c&0x7f] = P(zNm)!=0;
if( a[c&0x7f] ) aCap[i++] = c;
}
aCap[i] = 0;
bHasNewCaps = bIsNew || userHasNewCaps(zOldCaps, &aCap[0]);
zPw = P("pw");
zLogin = P("login");
if( strlen(zLogin)==0 ){
const char *zRef = cgi_referer("setup_ulist");
style_header("User Creation Error");
@ <span class="loginError">Empty login not allowed.</span>
@
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 |
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
@ [Bummer]</a></p>
style_finish_page();
return;
}
cgi_csrf_verify();
db_unprotect(PROTECT_USER);
| | | | > | | | > | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
@ [Bummer]</a></p>
style_finish_page();
return;
}
cgi_csrf_verify();
db_unprotect(PROTECT_USER);
uid = db_int(0,
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now()) "
"RETURNING uid",
uid, zLogin, P("info"), zPw, &aCap[0]);
assert( uid>0 );
if( zOldLogin && fossil_strcmp(zLogin, zOldLogin)!=0 ){
if( alert_tables_exist() ){
/* Rename matching subscriber entry, else the user cannot
re-subscribe with their same email address. */
db_multi_exec("UPDATE subscriber SET suname=%Q WHERE suname=%Q",
zLogin, zOldLogin);
}
admin_log( "Renamed user [%q] to [%q].", zOldLogin, zLogin );
}
db_protect_pop();
setup_incr_cfgcnt();
admin_log( "%s user [%q] with capabilities [%q].",
bIsNew ? "Added" : "Updated",
zLogin, &aCap[0] );
if( atoi(PD("all","0"))>0 ){
Blob sql;
char *zErr = 0;
blob_zero(&sql);
if( zOldLogin==0 ){
blob_appendf(&sql,
"INSERT INTO user(login)"
|
| ︙ | ︙ | |||
494 495 496 497 498 499 500 |
"UPDATE user SET login=%Q,"
" pw=coalesce(shared_secret(%Q,%Q,"
"(SELECT value FROM config WHERE name='project-code')),pw),"
" info=%Q,"
" cap=%Q,"
" mtime=now()"
" WHERE login=%Q;",
| | | > > > > > > | > < | 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 |
"UPDATE user SET login=%Q,"
" pw=coalesce(shared_secret(%Q,%Q,"
"(SELECT value FROM config WHERE name='project-code')),pw),"
" info=%Q,"
" cap=%Q,"
" mtime=now()"
" WHERE login=%Q;",
zLogin, P("pw"), zLogin, P("info"), &aCap[0],
zOldLogin
);
db_unprotect(PROTECT_USER);
login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr);
db_protect_pop();
blob_reset(&sql);
admin_log( "Updated user [%q] in all login groups "
"with capabilities [%q].",
zLogin, &aCap[0] );
if( zErr ){
const char *zRef = cgi_referer("setup_ulist");
style_header("User Change Error");
admin_log( "Error updating user '%q': %s'.", zLogin, zErr );
@ <span class="loginError">%h(zErr)</span>
@
@ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)">
@ [Bummer]</a></p>
style_finish_page();
if( bHasNewCaps ){
alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
}
return;
}
}
if( bHasNewCaps ){
alert_user_elevation(zLogin, uid, bIsNew, zOldCaps, &aCap[0]);
}
cgi_redirect(cgi_referer("setup_ulist"));
return;
}
/* Load the existing information about the user, if any
*/
zLogin = "";
zInfo = "";
zCap = zOldCaps;
zPw = "";
for(i='a'; i<='z'; i++) oa[i] = "";
for(i='0'; i<='9'; i++) oa[i] = "";
for(i='A'; i<='Z'; i++) oa[i] = "";
if( uid ){
assert( zCap );
zLogin = db_text("", "SELECT login FROM user WHERE uid=%d", uid);
zInfo = db_text("", "SELECT info FROM user WHERE uid=%d", uid);
zPw = db_text("", "SELECT pw FROM user WHERE uid=%d", uid);
for(i=0; zCap[i]; i++){
char c = zCap[i];
if( (c>='a' && c<='z') || (c>='0' && c<='9') || (c>='A' && c<='Z') ){
oa[c&0x7f] = " checked=\"checked\"";
}
}
|
| ︙ | ︙ |
Changes to src/sitemap.c.
| ︙ | ︙ | |||
291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
}
if( g.perm.Read ){
@ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
}
@ <li>%z(href("%R/test-builtin-files"))List of built-in files</a></li>
@ <li>%z(href("%R/mimetype_list"))List of MIME types</a></li>
@ <li>%z(href("%R/hash-color-test"))Hash color test</a>
if( g.perm.Admin ){
@ <li>%z(href("%R/test-backlinks"))List of backlinks</a></li>
@ <li>%z(href("%R/test-backlink-timeline"))Backlink timeline</a></li>
@ <li>%z(href("%R/phantoms"))List of phantom artifacts</a></li>
@ <li>%z(href("%R/test-warning"))Error Log test page</a></li>
@ <li>%z(href("%R/repo_stat1"))Repository <tt>sqlite_stat1</tt> table</a>
@ <li>%z(href("%R/repo_schema"))Repository schema</a></li>
| > | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
}
if( g.perm.Read ){
@ <li>%z(href("%R/test-rename-list"))List of file renames</a></li>
}
@ <li>%z(href("%R/test-builtin-files"))List of built-in files</a></li>
@ <li>%z(href("%R/mimetype_list"))List of MIME types</a></li>
@ <li>%z(href("%R/hash-color-test"))Hash color test</a>
@ <li>%z(href("%R/test-bgcolor"))Background color test</a>
if( g.perm.Admin ){
@ <li>%z(href("%R/test-backlinks"))List of backlinks</a></li>
@ <li>%z(href("%R/test-backlink-timeline"))Backlink timeline</a></li>
@ <li>%z(href("%R/phantoms"))List of phantom artifacts</a></li>
@ <li>%z(href("%R/test-warning"))Error Log test page</a></li>
@ <li>%z(href("%R/repo_stat1"))Repository <tt>sqlite_stat1</tt> table</a>
@ <li>%z(href("%R/repo_schema"))Repository schema</a></li>
|
| ︙ | ︙ |
Changes to src/sqlcmd.c.
| ︙ | ︙ | |||
233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
}
if( g.zConfigDbName ){
char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
g.zConfigDbName);
sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
/* Arrange to trace close operations so that static prepared statements
** will get cleaned up when the shell closes the database connection */
if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
db_protect_only(PROTECT_NONE);
sqlite3_set_authorizer(db, db_top_authorizer, db);
if( local_bSqlCmdTest ){
| > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
}
if( g.zConfigDbName ){
char *zSql = sqlite3_mprintf("ATTACH %Q AS 'configdb' KEY ''",
g.zConfigDbName);
sqlite3_exec(db, zSql, 0, 0, 0);
sqlite3_free(zSql);
}
(void)timeline_query_for_tty(); /* Registers wiki_to_text() as side-effect */
/* Arrange to trace close operations so that static prepared statements
** will get cleaned up when the shell closes the database connection */
if( g.fSqlTrace ) mTrace |= SQLITE_TRACE_PROFILE;
sqlite3_trace_v2(db, mTrace, db_sql_trace, 0);
db_protect_only(PROTECT_NONE);
sqlite3_set_authorizer(db, db_top_authorizer, db);
if( local_bSqlCmdTest ){
|
| ︙ | ︙ |
Changes to src/stash.c.
| ︙ | ︙ | |||
754 755 756 757 758 759 760 |
){
int fBaseline = 0;
DiffConfig DCfg;
if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
fBaseline = 1;
}
| | | 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 |
){
int fBaseline = 0;
DiffConfig DCfg;
if( strstr(zCmd,"show")!=0 || strstr(zCmd,"cat")!=0 ){
fBaseline = 1;
}
if( find_option("tk",0,0)!=0 || gdiff_using_tk(zCmd[0]=='g') ){
db_close(0);
diff_tk(fBaseline ? "stash show" : "stash diff", 3);
return;
}
diff_options(&DCfg, zCmd[0]=='g', 0);
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
stash_diff(stashid, fBaseline, &DCfg);
|
| ︙ | ︙ |
Changes to src/statrep.c.
| ︙ | ︙ | |||
316 317 318 319 320 321 322 323 324 325 326 |
&& rNowFraction>0.05
&& nCount>0
&& nMaxEvents>0
){
/* If the timespan covered by this row contains "now", then project
** the number of changes until the completion of the timespan and
** show a dashed box of that projection. */
int nExtra = (int)(((double)nCount)/rNowFraction) - nCount;
int nXSize = (100 * nExtra)/nMaxEvents;
@ <span class='statistics-report-graph-line' \
@ style='display:inline-block;min-width:%d(nSize)%%;'> </span>\
| > | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
&& rNowFraction>0.05
&& nCount>0
&& nMaxEvents>0
){
/* If the timespan covered by this row contains "now", then project
** the number of changes until the completion of the timespan and
** show a dashed box of that projection. */
int nProj = (int)(((double)nCount)/rNowFraction);
int nExtra = (int)(((double)nCount)/rNowFraction) - nCount;
int nXSize = (100 * nExtra)/nMaxEvents;
@ <span class='statistics-report-graph-line' \
@ style='display:inline-block;min-width:%d(nSize)%%;'> </span>\
@ <span class='statistics-report-graph-extra' title='%d(nProj)' \
@ style='display:inline-block;min-width:%d(nXSize)%%;'> </span>\
}else{
@ <div class='statistics-report-graph-line' \
@ style='width:%d(nSize)%%;'> </div> \
}
@ </td>
@ </tr>
|
| ︙ | ︙ | |||
745 746 747 748 749 750 751 |
cgi_printf("<td style='white-space: nowrap;'>");
if( nCount ){
if( zCurrentWeek!=0
&& strcmp(zWeek, zCurrentWeek)==0
&& rNowFraction>0.05
&& nMaxEvents>0
){
| | > | | 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 |
cgi_printf("<td style='white-space: nowrap;'>");
if( nCount ){
if( zCurrentWeek!=0
&& strcmp(zWeek, zCurrentWeek)==0
&& rNowFraction>0.05
&& nMaxEvents>0
){
/* If the timespan covered by this row contains "now", then project
** the number of changes until the completion of the week and
** show a dashed box of that projection. */
int nProj = (int)(((double)nCount)/rNowFraction);
int nExtra = (int)(((double)nCount)/rNowFraction) - nCount;
int nXSize = (100 * nExtra)/nMaxEvents;
@ <span class='statistics-report-graph-line' \
@ style='display:inline-block;min-width:%d(nSize)%%;'> </span>\
@ <span class='statistics-report-graph-extra' title='%d(nProj)' \
@ style='display:inline-block;min-width:%d(nXSize)%%;'> </span>\
}else{
@ <div class='statistics-report-graph-line' \
@ style='width:%d(nSize)%%;'> </div> \
}
}
cgi_printf("</td></tr>\n");
|
| ︙ | ︙ |
Changes to src/style.c.
| ︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
for(i=j=0; (c = allCap[j])!=0; j++){
if( login_has_capability(&c, 1, LOGIN_ANON)
&& !login_has_capability(&c, 1, 0) ) zCap[i++] = c;
}
zCap[i] = 0;
return zCap;
}
/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 |
for(i=j=0; (c = allCap[j])!=0; j++){
if( login_has_capability(&c, 1, LOGIN_ANON)
&& !login_has_capability(&c, 1, 0) ) zCap[i++] = c;
}
zCap[i] = 0;
return zCap;
}
/*
** WEBPAGE: test-title
**
** Render a test page in which the page title is set by the "title"
** query parameter. This can be used to show that HTML or Javascript
** content in the title does not leak through into generated page, resulting
** in an XSS issue.
**
** Due to the potential for abuse, this webpage is only available to
** administrators.
*/
void page_test_title(void){
const char *zTitle;
login_check_credentials();
if( !g.perm.Admin ){
login_needed(0);
}
zTitle = P("title");
if( zTitle==0 ){
zTitle = "(No Title)";
}
style_header("%s", zTitle);
@ <p>
@ This page sets its title to the value of the "title" query parameter.
@ The form below is a convenient way to set the title query parameter:
@
@ <form method="GET">
@ Title: <input type="text" size="50" name="title" value="%h(zTitle)">
@ <input type="submit" value="Submit">
@ </form>
style_finish_page();
}
/*
** WEBPAGE: test_env
**
** Display CGI-variables and other aspects of the run-time
** environment, for debugging and trouble-shooting purposes.
*/
|
| ︙ | ︙ |
Changes to src/tar.c.
| ︙ | ︙ | |||
497 498 499 500 501 502 503 |
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
int flg, eflg = 0;
mTime = (unsigned)((pManifest->rDate - 2440587.5)*86400.0);
if( pTar ) tar_begin(mTime);
| | | 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
int flg, eflg = 0;
mTime = (unsigned)((pManifest->rDate - 2440587.5)*86400.0);
if( pTar ) tar_begin(mTime);
flg = db_get_manifest_setting(blob_str(&hash));
if( flg ){
/* eflg is the effective flags, taking include/exclude into account */
if( (pInclude==0 || glob_match(pInclude, "manifest"))
&& !glob_match(pExclude, "manifest")
&& (flg & MFESTFLG_RAW) ){
eflg |= MFESTFLG_RAW;
}
|
| ︙ | ︙ |
Changes to src/terminal.c.
| ︙ | ︙ | |||
58 59 60 61 62 63 64 |
*/
int terminal_get_size(TerminalSize *t){
memset(t, 0, sizeof(*t));
#if defined(TIOCGSIZE)
{
struct ttysize ts;
| | > > > | > > > | > > > | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
*/
int terminal_get_size(TerminalSize *t){
memset(t, 0, sizeof(*t));
#if defined(TIOCGSIZE)
{
struct ttysize ts;
if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)>=0
|| ioctl(STDOUT_FILENO, TIOCGSIZE, &ts)>=0
|| ioctl(STDERR_FILENO, TIOCGSIZE, &ts)>=0
){
t->nColumns = ts.ts_cols;
t->nLines = ts.ts_lines;
return 1;
}
return 0;
}
#elif defined(TIOCGWINSZ)
{
struct winsize ws;
if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)>=0
|| ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)>=0
|| ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)>=0
){
t->nColumns = ws.ws_col;
t->nLines = ws.ws_row;
return 1;
}
return 0;
}
#elif defined(_WIN32)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)
|| GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbi)
){
t->nColumns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
t->nLines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
return 1;
}
return 0;
}
#else
|
| ︙ | ︙ | |||
127 128 129 130 131 132 133 |
** If the size cannot be determined, two zeros are shown.
*/
void test_terminal_size_cmd(void){
TerminalSize ts;
terminal_get_size(&ts);
fossil_print("%d %d\n", ts.nColumns, ts.nLines);
}
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
** If the size cannot be determined, two zeros are shown.
*/
void test_terminal_size_cmd(void){
TerminalSize ts;
terminal_get_size(&ts);
fossil_print("%d %d\n", ts.nColumns, ts.nLines);
}
/*
** Return true if it is reasonable is emit VT100 escape codes.
*/
int terminal_is_vt100(void){
char *zNoColor;
#ifdef _WIN32
if( !win32_terminal_is_vt100(1) ) return 0;
#endif /* _WIN32 */
if( !fossil_isatty(1) ) return 0;
zNoColor =fossil_getenv("NO_COLOR");
if( zNoColor==0 ) return 1;
if( zNoColor[0]==0 ) return 1;
if( is_false(zNoColor) ) return 1;
return 0;
}
#ifdef _WIN32
/*
** Return true if the Windows console supports VT100 escape codes.
**
** Support for VT100 escape codes is enabled by default in Windows Terminal
** on Windows 10 and Windows 11, and disabled by default in Legacy Consoles
** and on older versions of Windows. Programs can turn on VT100 support for
** Legacy Consoles using the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag.
**
** NOTE: If this function needs to be called in more complex scenarios with
** reassigned stdout and stderr streams, the following CRT calls are useful
** to translate from CRT streams to file descriptors and to Win32 handles:
**
** HANDLE hOutputHandle = (HANDLE)_get_osfhandle(_fileno(<FILE*>));
*/
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
int win32_terminal_is_vt100(int fd){
HANDLE hConsole = NULL;
DWORD dwConsoleMode;
switch( fd ){
case 1:
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
break;
case 2:
hConsole = GetStdHandle(STD_ERROR_HANDLE);
break;
}
if( GetConsoleMode(hConsole,&dwConsoleMode) ){
return (dwConsoleMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)!=0;
}
return 0;
}
#endif /* _WIN32 */
|
Changes to src/th_main.c.
| ︙ | ︙ | |||
694 695 696 697 698 699 700 701 702 703 704 705 706 707 |
Blob src;
blob_init(&src, (char*)argv[1], argl[1]);
wiki_convert(&src, 0, flags);
blob_reset(&src);
}
return TH_OK;
}
/*
** TH1 command: htmlize STRING
**
** Escape all characters of STRING which have special meaning in HTML.
** Return a new string result.
*/
| > > > > > > > > > > > > > > > > > > > > > | 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
Blob src;
blob_init(&src, (char*)argv[1], argl[1]);
wiki_convert(&src, 0, flags);
blob_reset(&src);
}
return TH_OK;
}
/*
** TH1 command: wiki_assoc STRING STRING
**
** Render an associated wiki page. The first string is the namespace
** (e.g. "checkin", "branch", "ticket"). The second is the ID of the
** associated object. See wiki_render_associated().
*/
static int wikiAssocCmd(
Th_Interp *interp,
void *p,
int argc,
const char **argv,
int *argl
){
if( argc!=3 ){
return Th_WrongNumArgs(interp, "wiki_assoc STRING STRING");
}
wiki_render_associated((char*)argv[1], (char*)argv[2], WIKIASSOC_FULL_TITLE);
return TH_OK;
}
/*
** TH1 command: htmlize STRING
**
** Escape all characters of STRING which have special meaning in HTML.
** Return a new string result.
*/
|
| ︙ | ︙ | |||
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 |
{"trace", traceCmd, 0},
{"stime", stimeCmd, 0},
{"unversioned", unversionedCmd, 0},
{"utime", utimeCmd, 0},
{"verifyCsrf", verifyCsrfCmd, 0},
{"verifyLogin", verifyLoginCmd, 0},
{"wiki", wikiCmd, (void*)&aFlags[0]},
{0, 0, 0}
};
if( g.thTrace ){
Th_Trace("th1-init 0x%x => 0x%x<br>\n", g.th1Flags, flags);
}
if( needConfig ){
/*
| > | 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 |
{"trace", traceCmd, 0},
{"stime", stimeCmd, 0},
{"unversioned", unversionedCmd, 0},
{"utime", utimeCmd, 0},
{"verifyCsrf", verifyCsrfCmd, 0},
{"verifyLogin", verifyLoginCmd, 0},
{"wiki", wikiCmd, (void*)&aFlags[0]},
{"wiki_assoc", wikiAssocCmd, 0},
{0, 0, 0}
};
if( g.thTrace ){
Th_Trace("th1-init 0x%x => 0x%x<br>\n", g.th1Flags, flags);
}
if( needConfig ){
/*
|
| ︙ | ︙ |
Changes to src/timeline.c.
| ︙ | ︙ | |||
203 204 205 206 207 208 209 | int prevTagid = 0; int suppressCnt = 0; char zPrevDate[20]; GraphContext *pGraph = 0; int prevWasDivider = 0; /* True if previous output row was <hr> */ int fchngQueryInit = 0; /* True if fchngQuery is initialized */ Stmt fchngQuery; /* Query for file changes on check-ins */ | < > > > > > > > > > > > > > > > > > < < < < | | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
int prevTagid = 0;
int suppressCnt = 0;
char zPrevDate[20];
GraphContext *pGraph = 0;
int prevWasDivider = 0; /* True if previous output row was <hr> */
int fchngQueryInit = 0; /* True if fchngQuery is initialized */
Stmt fchngQuery; /* Query for file changes on check-ins */
int pendingEndTr = 0; /* True if a </td></tr> is needed */
int vid = 0; /* Current check-out version */
int dateFormat = 0; /* 0: HH:MM (default) */
int bCommentGitStyle = 0; /* Only show comments through first blank line */
const char *zStyle; /* Sub-name for classes for the style */
const char *zDateFmt;
int iTableId = timeline_tableid();
int bTimestampLinksToInfo; /* True if timestamp hyperlinks go to the /info
** page rather than the /timeline page */
if( cgi_is_loopback(g.zIpAddr) && db_open_local(0) ){
vid = db_lget_int("checkout", 0);
}
zPrevDate[0] = 0;
mxWikiLen = db_get_int("timeline-max-comment", 0);
dateFormat = db_get_int("timeline-date-format", 0);
/*
** SETTING: timeline-truncate-at-blank boolean default=off
**
** If enabled, check-in comments displayed on the timeline are truncated
** at the first blank line of the comment text. The comment text after
** the first blank line is only seen in the /info or similar pages that
** show details about the check-in.
*/
bCommentGitStyle = db_get_int("timeline-truncate-at-blank", 0);
/*
** SETTING: timeline-tslink-info boolean default=off
**
** The hyperlink on the timestamp associated with each timeline entry,
** on the far left-hand side of the screen, normally targets another
** /timeline page that shows the entry in context. However, if this
** option is turned on, that hyperlink targets the /info page showing
** the details of the entry.
*/
bTimestampLinksToInfo = db_get_boolean("timeline-tslink-info", 0);
if( (tmFlags & TIMELINE_VIEWS)==0 ){
tmFlags |= timeline_ss_cookie();
}
if( tmFlags & TIMELINE_COLUMNAR ){
zStyle = "Columnar";
}else if( tmFlags & TIMELINE_COMPACT ){
zStyle = "Compact";
}else if( tmFlags & TIMELINE_VERBOSE ){
zStyle = "Verbose";
}else if( tmFlags & TIMELINE_CLASSIC ){
zStyle = "Classic";
}else{
zStyle = "Modern";
}
zDateFmt = P("datefmt");
if( zDateFmt ) dateFormat = atoi(zDateFmt);
if( tmFlags & TIMELINE_GRAPH ){
pGraph = graph_init();
}
if( (tmFlags & TIMELINE_CHPICK)!=0
&& !db_table_exists("repository","cherrypick")
){
tmFlags &= ~TIMELINE_CHPICK;
}
@ <table id="timelineTable%d(iTableId)" class="timelineTable"> \
@ <!-- tmFlags: 0x%x(tmFlags) -->
blob_zero(&comment);
while( db_step(pQuery)==SQLITE_ROW ){
int rid = db_column_int(pQuery, 0);
const char *zUuid = db_column_text(pQuery, 1);
int isLeaf = db_column_int(pQuery, 5);
const char *zBgClr = db_column_text(pQuery, 6);
const char *zDate = db_column_text(pQuery, 2);
const char *zType = db_column_text(pQuery, 7);
const char *zUser = db_column_text(pQuery, 4);
const char *zTagList = db_column_text(pQuery, 8);
int tagid = db_column_int(pQuery, 9);
const char *zDispUser = zUser && zUser[0] ? zUser : "anonymous";
char *zBr = 0; /* Branch */
int commentColumn = 3; /* Column containing comment text */
int modPending; /* Pending moderation */
char *zDateLink; /* URL for the link on the timestamp */
int drawDetailEllipsis; /* True to show ellipsis in place of detail */
int gidx = 0; /* Graph row identifier */
int isSelectedOrCurrent = 0; /* True if current row is selected */
const char *zExtraClass = "";
|
| ︙ | ︙ | |||
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
}
}else{
zDateLink = mprintf("<a>");
}
@ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
@ <td class="timelineGraph">
if( tmFlags & (TIMELINE_UCOLOR|TIMELINE_DELTA|TIMELINE_NOCOLOR) ){
if( tmFlags & TIMELINE_UCOLOR ){
zBgClr = zUser ? user_color(zUser) : 0;
}else if( tmFlags & TIMELINE_NOCOLOR ){
zBgClr = 0;
}else if( zType[0]=='c' ){
static Stmt qdelta;
db_static_prepare(&qdelta, "SELECT baseid IS NULL FROM plink"
" WHERE cid=:rid");
db_bind_int(&qdelta, ":rid", rid);
if( db_step(&qdelta)!=SQLITE_ROW ){
zBgClr = 0; /* Not a check-in */
}else if( db_column_int(&qdelta, 0) ){
zBgClr = hash_color("b"); /* baseline manifest */
}else{
zBgClr = hash_color("f"); /* delta manifest */
}
db_reset(&qdelta);
}
}
if( zType[0]=='c'
&& (pGraph || zBgClr==0 || (tmFlags & (TIMELINE_BRCOLOR|TIMELINE_DELTA))!=0)
){
| > > > > > < < < < < | < > > | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
}
}else{
zDateLink = mprintf("<a>");
}
@ <td class="timelineTime">%z(zDateLink)%s(zTime)</a></td>
@ <td class="timelineGraph">
if( tmFlags & (TIMELINE_UCOLOR|TIMELINE_DELTA|TIMELINE_NOCOLOR) ){
/* Don't use the requested background color. Use the background color
** override from query parameters instead. */
if( tmFlags & TIMELINE_UCOLOR ){
zBgClr = zUser ? user_color(zUser) : 0;
}else if( tmFlags & TIMELINE_NOCOLOR ){
zBgClr = 0;
}else if( zType[0]=='c' ){
static Stmt qdelta;
db_static_prepare(&qdelta, "SELECT baseid IS NULL FROM plink"
" WHERE cid=:rid");
db_bind_int(&qdelta, ":rid", rid);
if( db_step(&qdelta)!=SQLITE_ROW ){
zBgClr = 0; /* Not a check-in */
}else if( db_column_int(&qdelta, 0) ){
zBgClr = hash_color("b"); /* baseline manifest */
}else{
zBgClr = hash_color("f"); /* delta manifest */
}
db_reset(&qdelta);
}
}else{
/* Make sure the user-specified background color is reasonable */
zBgClr = reasonable_bg_color(zBgClr, 0);
}
if( zType[0]=='c'
&& (pGraph || zBgClr==0 || (tmFlags & (TIMELINE_BRCOLOR|TIMELINE_DELTA))!=0)
){
zBr = branch_of_rid(rid);
if( zBgClr==0 || (tmFlags & TIMELINE_BRCOLOR)!=0 ){
/* If no background color is specified, use a color based on the
** branch name */
if( tmFlags & (TIMELINE_DELTA|TIMELINE_NOCOLOR) ){
}else if( zBr==0 || strcmp(zBr,"trunk")==0 ){
zBgClr = 0;
}else{
zBgClr = hash_color(zBr);
}
}
|
| ︙ | ︙ | |||
457 458 459 460 461 462 463 |
nCherrypick++;
}
db_reset(&qcherrypick);
}
gidx = graph_add_row(pGraph, rid, nParent, nCherrypick, aParent,
zBr, zBgClr, zUuid,
isLeaf ? isLeaf + 2 * has_closed_tag(rid) : 0);
| < > | 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
nCherrypick++;
}
db_reset(&qcherrypick);
}
gidx = graph_add_row(pGraph, rid, nParent, nCherrypick, aParent,
zBr, zBgClr, zUuid,
isLeaf ? isLeaf + 2 * has_closed_tag(rid) : 0);
@ <div id="m%d(gidx)" class="tl-nodemark"></div>
}else if( zType[0]=='e' && pGraph && zBgClr && zBgClr[0] ){
/* For technotes, make a graph node with nParent==(-1). This will
** not actually draw anything on the graph, but it will set the
** background color of the timeline entry */
gidx = graph_add_row(pGraph, rid, -1, 0, 0, zBr, zBgClr, zUuid, 0);
@ <div id="m%d(gidx)" class="tl-nodemark"></div>
}
fossil_free(zBr);
@</td>
if( !isSelectedOrCurrent ){
@ <td class="timeline%s(zStyle)Cell%s(zExtraClass)" id='mc%d(gidx)'>
}else{
@ <td class="timeline%s(zStyle)Cell%s(zExtraClass)">
}
if( pGraph ){
|
| ︙ | ︙ | |||
1098 1099 1100 1101 1102 1103 1104 |
@ event.mtime AS mtime
@ FROM event CROSS JOIN blob
@ WHERE blob.rid=event.objid
;
return zBase;
}
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
@ event.mtime AS mtime
@ FROM event CROSS JOIN blob
@ WHERE blob.rid=event.objid
;
return zBase;
}
/*
** zDate is a localtime date. Insert records into the
** "timeline" table to cause <hr> to be inserted on zDate.
*/
static int timeline_add_divider(double rDate){
int rid = db_int(-1,
"SELECT rid FROM timeline ORDER BY abs(sortby-%.16g) LIMIT 1", rDate
|
| ︙ | ︙ | |||
1390 1391 1392 1393 1394 1395 1396 | ** first check-in. If there are no check-ins in the decendent ** or ancestor set of check-in iFrom that match the tag, then ** return 0. */ static int timeline_endpoint( int iFrom, /* Starting point */ const char *zEnd, /* Tag we are searching for */ | | | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
** first check-in. If there are no check-ins in the decendent
** or ancestor set of check-in iFrom that match the tag, then
** return 0.
*/
static int timeline_endpoint(
int iFrom, /* Starting point */
const char *zEnd, /* Tag we are searching for */
int bForward /* 1: forwards in time (descendants) 0: backwards */
){
int tagId;
int endId = 0;
Stmt q;
int ans = 0;
tagId = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zEnd);
|
| ︙ | ︙ | |||
1417 1418 1419 1420 1421 1422 1423 |
" FROM dx, plink"
" WHERE plink.pid=dx.id"
" AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event"
" WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid)"
" ORDER BY plink.mtime)"
"SELECT id FROM dx, tagxref"
| | > | 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 |
" FROM dx, plink"
" WHERE plink.pid=dx.id"
" AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event"
" WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid)"
" ORDER BY plink.mtime)"
"SELECT id FROM dx, tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=id"
" ORDER BY dx.mtime LIMIT 1",
iFrom, iFrom, tagId, tagId
);
}else{
db_prepare(&q,
"WITH RECURSIVE dx(id,mtime) AS ("
" SELECT %d, event.mtime FROM event WHERE objid=%d"
" UNION"
|
| ︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 |
" FROM dx, plink, event"
" WHERE plink.cid=dx.id AND event.objid=plink.pid"
" AND event.mtime>=(SELECT min(event.mtime) FROM tagxref, event"
" WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid)"
" ORDER BY event.mtime DESC)"
"SELECT id FROM dx, tagxref"
| | > | 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 |
" FROM dx, plink, event"
" WHERE plink.cid=dx.id AND event.objid=plink.pid"
" AND event.mtime>=(SELECT min(event.mtime) FROM tagxref, event"
" WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
" AND event.objid=tagxref.rid)"
" ORDER BY event.mtime DESC)"
"SELECT id FROM dx, tagxref"
" WHERE tagid=%d AND tagtype>0 AND rid=id"
" ORDER BY dx.mtime DESC LIMIT 1",
iFrom, iFrom, tagId, tagId
);
}else{
db_prepare(&q,
"WITH RECURSIVE dx(id,mtime) AS ("
" SELECT %d, event.mtime FROM event WHERE objid=%d"
" UNION"
|
| ︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 | } /* ** COMMAND: test-endpoint ** ** Usage: fossil test-endpoint BASE TAG ?OPTIONS? ** | | | | | 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
}
/*
** COMMAND: test-endpoint
**
** Usage: fossil test-endpoint BASE TAG ?OPTIONS?
**
** Show the first check-in with TAG that is a descendant or ancestor
** of BASE. The first descendant checkin is shown by default. Use
** the --backto to see the first ancestor checkin.
**
** Options:
**
** --backto Show ancestor. Others defaults to descendants.
*/
void timeline_test_endpoint(void){
int bForward = find_option("backto",0,0)==0;
int from_rid;
int ans;
db_find_and_open_repository(0, 0);
verify_all_options();
|
| ︙ | ︙ | |||
1581 1582 1583 1584 1585 1586 1587 | ** d2=CKIN2 ... Use CKIN2 if CHECKIN is not found ** ft=DESCENDANT ... going forward to DESCENDANT ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** dp2=CKIN2 Same as 'd2=CKIN2&p2=CKIN2' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN "Back To". Show ancenstors going back to CHECKIN ** p=CX ... from CX back to time of CHECKIN | | | | 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | ** d2=CKIN2 ... Use CKIN2 if CHECKIN is not found ** ft=DESCENDANT ... going forward to DESCENDANT ** dp=CHECKIN Same as 'd=CHECKIN&p=CHECKIN' ** dp2=CKIN2 Same as 'd2=CKIN2&p2=CKIN2' ** df=CHECKIN Same as 'd=CHECKIN&n1=all&nd'. Mnemonic: "Derived From" ** bt=CHECKIN "Back To". Show ancenstors going back to CHECKIN ** p=CX ... from CX back to time of CHECKIN ** from=CX ... path from CX back to CHECKIN ** ft=CHECKIN "Forward To": Show decendents forward to CHECKIN ** d=CX ... from CX up to the time of CHECKIN ** from=CX ... path from CX up to CHECKIN ** t=TAG Show only check-ins with the given TAG ** r=TAG Same as 't=TAG&rel'. Mnemonic: "Related" ** tl=TAGLIST Same as 't=TAGLIST&ms=brlist'. Mnemonic: "Tag List" ** rl=TAGLIST Same as 'r=TAGLIST&ms=brlist'. Mnemonic: "Related List" ** ml=TAGLIST Same as 'tl=TAGLIST&mionly'. Mnemonic: "Merge-in List" ** sl=TAGLIST "Sort List". Draw TAGLIST branches ordered left to right. ** rel Show related check-ins as well as those matching t=TAG |
| ︙ | ︙ | |||
1609 1610 1611 1612 1613 1614 1615 | ** ncp Omit cherrypick merges ** nd Do not highlight the focus check-in ** nsm Omit the submenu ** nc Omit all graph colors other than highlights ** v Show details of files changed ** vfx Show complete text of forum messages ** f=CHECKIN Family (immediate parents and children) of CHECKIN | | | | | | > | | | | | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 | ** ncp Omit cherrypick merges ** nd Do not highlight the focus check-in ** nsm Omit the submenu ** nc Omit all graph colors other than highlights ** v Show details of files changed ** vfx Show complete text of forum messages ** f=CHECKIN Family (immediate parents and children) of CHECKIN ** from=CHECKIN Path through common ancestor from CHECKIN... ** to=CHECKIN ... to this ** to2=CHECKIN ... backup name if to= doesn't resolve ** shortest ... pick path with least number of nodes ** rel ... also show related checkins ** min ... hide long sequences along same branch ** bt=PRIOR ... path from CHECKIN back to PRIOR ** ft=LATER ... path from CHECKIN forward to LATER ** me=CHECKIN Most direct path from CHECKIN... ** you=CHECKIN ... to this ** rel ... also show related checkins ** uf=FILE_HASH Show only check-ins that contain the given file version ** All qualifying check-ins are shown unless there is ** also an n= or n1= query parameter. ** chng=GLOBLIST Show only check-ins that involve changes to a file whose ** name matches one of the comma-separate GLOBLIST ** brbg Background color determined by branch name ** ubg Background color determined by user |
| ︙ | ︙ | |||
1705 1706 1707 1708 1709 1710 1711 |
int tmFlags = 0; /* Timeline flags */
const char *zThisTag = 0; /* Suppress links to this tag */
const char *zThisUser = 0; /* Suppress links to this user */
HQuery url; /* URL for various branch links */
int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */
const char *zTo2 = 0;
int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */
| | | > | 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 |
int tmFlags = 0; /* Timeline flags */
const char *zThisTag = 0; /* Suppress links to this tag */
const char *zThisUser = 0; /* Suppress links to this user */
HQuery url; /* URL for various branch links */
int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */
const char *zTo2 = 0;
int to_rid = name_choice("to","to2",&zTo2); /* to= for path timelines */
int bShort = P("shortest")!=0; /* shortest possible path */
int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */
int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */
int pd_rid;
const char *zDPNameP, *zDPNameD; /* Value of p=, d=, or dp= params */
double rBefore, rAfter, rCirca; /* Boundary times */
const char *z;
char *zOlderButton = 0; /* URL for Older button at the bottom */
char *zOlderButtonLabel = 0; /* Label for the Older Button */
char *zNewerButton = 0; /* URL for Newer button at the top */
char *zNewerButtonLabel = 0; /* Label for the Newer button */
int selectedRid = 0; /* Show a highlight on this RID */
int secondaryRid = 0; /* Show secondary highlight */
int disableY = 0; /* Disable type selector on submenu */
int advancedMenu = 0; /* Use the advanced menu design */
char *zPlural; /* Ending for plural forms */
int showCherrypicks = 1; /* True to show cherrypick merges */
int haveParameterN; /* True if n= query parameter present */
int from_to_mode = 0; /* 0: from,to. 1: from,ft 2: from,bt */
int showSql = PB("showsql"); /* True to show the SQL */
Blob allSql; /* Copy of all SQL text */
int bMin = P("min")!=0; /* True if "min" query parameter used */
login_check_credentials();
url_initialize(&url, "timeline");
cgi_query_parameters_to_url(&url);
blob_init(&allSql, 0, 0);
/* The "mionly" query parameter is like "rel", but shows merge-ins only */
|
| ︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 |
}
}
}else{
nEntry = 50;
}
/* Query parameters d=, p=, and f= and variants */
| | | | | 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 |
}
}
}else{
nEntry = 50;
}
/* Query parameters d=, p=, and f= and variants */
p_rid = name_choice("p","p2", &zDPNameP);
d_rid = name_choice("d","d2", &zDPNameD);
z = P("f");
f_rid = z ? name_to_typed_rid(z,"ci") : 0;
z = P("df");
if( z && (d_rid = name_to_typed_rid(z,"ci"))!=0 ){
nEntry = 0;
useDividers = 0;
cgi_replace_query_parameter("d",fossil_strdup(z));
zDPNameD = zDPNameP = z;
}
/* Undocumented query parameter to set JS mode */
builtin_set_js_delivery_mode(P("jsmode"),1);
secondaryRid = name_to_typed_rid(P("sel2"),"ci");
selectedRid = name_to_typed_rid(P("sel1"),"ci");
|
| ︙ | ︙ | |||
1808 1809 1810 1811 1812 1813 1814 |
** present or if this repository lacks a "cherrypick" table. */
if( PB("ncp") || !db_table_exists("repository","cherrypick") ){
showCherrypicks = 0;
}
/* To view the timeline, must have permission to read project data.
*/
| | > | 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 |
** present or if this repository lacks a "cherrypick" table. */
if( PB("ncp") || !db_table_exists("repository","cherrypick") ){
showCherrypicks = 0;
}
/* To view the timeline, must have permission to read project data.
*/
pd_rid = name_choice("dp","dp2",&zDPNameP);
if( pd_rid ){
p_rid = d_rid = pd_rid;
zDPNameD = zDPNameP;
}
if( (!g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki && !g.perm.RdForum)
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
|
| ︙ | ︙ | |||
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 |
PathNode *p = 0;
const char *zFrom = 0;
const char *zTo = 0;
Blob ins;
int nNodeOnPath = 0;
int commonAncs = 0; /* Common ancestors of me_rid and you_rid. */
int earlierRid = 0, laterRid = 0;
if( from_rid && to_rid ){
if( from_to_mode==0 ){
| > > | | | | 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 |
PathNode *p = 0;
const char *zFrom = 0;
const char *zTo = 0;
Blob ins;
int nNodeOnPath = 0;
int commonAncs = 0; /* Common ancestors of me_rid and you_rid. */
int earlierRid = 0, laterRid = 0;
int cost = bShort ? 0 : 1;
int nSkip = 0;
if( from_rid && to_rid ){
if( from_to_mode==0 ){
p = path_shortest(from_rid, to_rid, 0, 0, 0, cost);
}else if( from_to_mode==1 ){
p = path_shortest(from_rid, to_rid, 0, 1, 0, cost);
earlierRid = commonAncs = from_rid;
laterRid = to_rid;
}else{
p = path_shortest(to_rid, from_rid, 0, 1, 0, cost);
earlierRid = commonAncs = to_rid;
laterRid = from_rid;
}
zFrom = P("from");
zTo = zTo2 ? zTo2 : P("to");
}else{
commonAncs = path_common_ancestor(me_rid, you_rid);
|
| ︙ | ︙ | |||
2121 2122 2123 2124 2125 2126 2127 |
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS pathnode(x INTEGER PRIMARY KEY);"
);
if( p ){
int cnt = 4;
blob_init(&ins, 0, 0);
blob_append_sql(&ins, "INSERT INTO pathnode(x) VALUES(%d)", p->rid);
| > > > | > > | > | < | 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 |
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS pathnode(x INTEGER PRIMARY KEY);"
);
if( p ){
int cnt = 4;
blob_init(&ins, 0, 0);
blob_append_sql(&ins, "INSERT INTO pathnode(x) VALUES(%d)", p->rid);
if( p->u.pTo==0 ) bMin = 0;
for(p=p->u.pTo; p; p=p->u.pTo){
if( bMin
&& p->u.pTo!=0
&& fossil_strcmp(path_branch(p->pFrom),path_branch(p))==0
&& fossil_strcmp(path_branch(p),path_branch(p->u.pTo))==0
){
nSkip++;
}else if( cnt==8 ){
blob_append_sql(&ins, ",\n (%d)", p->rid);
cnt = 0;
}else{
cnt++;
blob_append_sql(&ins, ",(%d)", p->rid);
}
}
}
path_reset();
db_multi_exec("%s", blob_str(&ins)/*safe-for-%s*/);
blob_reset(&ins);
if( related ){
db_multi_exec(
|
| ︙ | ︙ | |||
2194 2195 2196 2197 2198 2199 2200 |
db_multi_exec("%s", blob_sql_text(&sql));
if( advancedMenu ){
style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
}
nNodeOnPath = db_int(0, "SELECT count(*) FROM temp.pathnode");
if( nNodeOnPath==1 && from_to_mode>0 ){
blob_appendf(&desc,"Check-in ");
| | | > | 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 |
db_multi_exec("%s", blob_sql_text(&sql));
if( advancedMenu ){
style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
}
nNodeOnPath = db_int(0, "SELECT count(*) FROM temp.pathnode");
if( nNodeOnPath==1 && from_to_mode>0 ){
blob_appendf(&desc,"Check-in ");
}else if( bMin ){
blob_appendf(&desc, "%d of %d check-ins along the path from ",
nNodeOnPath, nNodeOnPath+nSkip);
}else{
blob_appendf(&desc, "%d check-ins going from ", nNodeOnPath);
}
if( from_rid==selectedRid ){
blob_appendf(&desc, "<span class='timelineSelected'>");
}
blob_appendf(&desc, "%z%h</a>", href("%R/info/%h", zFrom), zFrom);
|
| ︙ | ︙ | |||
2223 2224 2225 2226 2227 2228 2229 |
blob_appendf(&desc, " and %d related check-in%s", nRelated,
nRelated>1 ? "s" : "");
}
}
}
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
| | | | > > > | > > > > > | < | < < < < > > > > > > > | < | < > > > > > > > > > > > > > | | | | | | | > > > > > > > > | < > > > > > > > > > > > | | | | | | | | | > > > > > > > > > > > > > | | > | | | | > | | > | | | | < < < < < < > | 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 |
blob_appendf(&desc, " and %d related check-in%s", nRelated,
nRelated>1 ? "s" : "");
}
}
}
addFileGlobDescription(zChng, &desc);
}else if( (p_rid || d_rid) && g.perm.Read && zTagSql==0 ){
/* If either p= or d= or both are present, ignore all other parameters
** other than n=, ft=, and bt= */
const char *zBaseName = 0;
int np = 0, nd;
const char *zBackTo = 0;
const char *zFwdTo = 0;
int ridBackTo = 0;
int ridFwdTo = 0;
int bBackAdded = 0; /* True if the zBackTo node was added */
int bFwdAdded = 0; /* True if the zBackTo node was added */
int bSeparateDandP = 0; /* p_rid & d_rid both exist and are distinct */
tmFlags |= TIMELINE_XMERGE | TIMELINE_FILLGAPS;
if( p_rid && d_rid && p_rid!=d_rid ){
bSeparateDandP = 1;
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok_d(rid INTEGER PRIMARY KEY)"
);
}else{
zBaseName = p_rid ? zDPNameP : zDPNameD;
}
db_multi_exec(
"CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY)"
);
add_extra_rids("ok", P("x"));
blob_append_sql(&sql, " AND event.objid IN ok");
nd = 0;
if( d_rid ){
double rStopTime = 9e99;
zFwdTo = P("ft");
if( zFwdTo && bSeparateDandP ){
if( zError==0 ){
zError = "Cannot use the ft= query parameter when both p= and d= "
"are used and have distinct values.";
}
zFwdTo = 0;
}
if( zFwdTo ){
double rStartDate = mtime_of_rid(d_rid, 0.0);
ridFwdTo = first_checkin_with_tag_after_date(zFwdTo, rStartDate);
if( ridFwdTo==0 ){
ridFwdTo = name_to_typed_rid(zBackTo,"ci");
}
if( ridFwdTo ){
if( !haveParameterN ) nEntry = 0;
rStopTime = mtime_of_rid(ridFwdTo, 9e99);
}
}else if( bSeparateDandP ){
rStopTime = mtime_of_rid(p_rid, 9e99);
nEntry = 0;
}
if( rStopTime<9e99 ){
rStopTime += 5.8e-6; /* Round up by 1/2 second */
}
db_multi_exec(
"WITH RECURSIVE dx(rid,mtime) AS (\n"
" SELECT %d, 0\n"
" UNION\n"
" SELECT plink.cid, plink.mtime FROM dx, plink\n"
" WHERE plink.pid=dx.rid\n"
" AND plink.mtime<=%.*g\n"
" ORDER BY 2\n"
")\n"
"INSERT OR IGNORE INTO ok SELECT rid FROM dx LIMIT %d",
d_rid, rStopTime<8e99 ? 17 : 2, rStopTime, nEntry<=0 ? -1 : nEntry+1
);
if( ridFwdTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridFwdTo) ){
db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridFwdTo);
bFwdAdded = 1;
}
if( bSeparateDandP ){
db_multi_exec(
"INSERT INTO ok_d SELECT rid FROM ok;"
"DELETE FROM ok;"
);
}else{
nd = db_int(0, "SELECT count(*)-1 FROM ok");
if( nd>=0 ) db_multi_exec("%s", blob_sql_text(&sql));
if( nd>0 || p_rid==0 ){
blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
}
if( useDividers && !selectedRid ) selectedRid = d_rid;
db_multi_exec("DELETE FROM ok");
}
}
if( p_rid ){
zBackTo = P("bt");
if( zBackTo && bSeparateDandP ){
if( zError==0 ){
zError = "Cannot use the bt= query parameter when both p= and d= "
"are used and have distinct values.";
}
zBackTo = 0;
}
if( zBackTo ){
double rDateLimit = mtime_of_rid(p_rid, 0.0);
ridBackTo = last_checkin_with_tag_before_date(zBackTo, rDateLimit);
if( ridBackTo==0 ){
ridBackTo = name_to_typed_rid(zBackTo,"ci");
}
if( ridBackTo && !haveParameterN ) nEntry = 0;
}else if( bSeparateDandP ){
ridBackTo = d_rid;
nEntry = 0;
}
compute_ancestors(p_rid, nEntry==0 ? 0 : nEntry+1, 0, ridBackTo);
if( ridBackTo && !db_exists("SELECT 1 FROM ok WHERE rid=%d",ridBackTo) ){
db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", ridBackTo);
bBackAdded = 1;
}
if( bSeparateDandP ){
db_multi_exec("DELETE FROM ok WHERE rid NOT IN ok_d;");
db_multi_exec("%s", blob_sql_text(&sql));
}else{
np = db_int(0, "SELECT count(*)-1 FROM ok");
if( np>0 || nd==0 ){
if( nd>0 ) blob_appendf(&desc, " and ");
blob_appendf(&desc, "%d ancestor%s", np, (1==np)?"":"s");
db_multi_exec("%s", blob_sql_text(&sql));
}
if( useDividers && !selectedRid ) selectedRid = p_rid;
}
}
if( bSeparateDandP ){
int n = db_int(0, "SELECT count(*) FROM ok");
blob_reset(&desc);
blob_appendf(&desc,
"%d check-ins that are both ancestors of %z%h</a>"
" and descendants of %z%h</a>",
n,
href("%R/info?name=%h",zDPNameP),zDPNameP,
href("%R/info?name=%h",zDPNameD),zDPNameD
);
ridBackTo = 0;
ridFwdTo = 0;
}else{
blob_appendf(&desc, " of %z%h</a>",
href("%R/info?name=%h", zBaseName), zBaseName);
}
if( ridBackTo ){
if( np==0 ){
blob_reset(&desc);
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> does not precede it)",
href("%R/info?name=%h",zBaseName), zBaseName,
href("%R/info?name=%h",zBackTo), zBackTo);
}else{
blob_appendf(&desc, " back to %z%h</a>%s",
href("%R/info?name=%h",zBackTo), zBackTo,
bBackAdded ? " (not a direct anscestor)" : "");
if( ridFwdTo && zFwdTo ){
blob_appendf(&desc, " and up to %z%h</a>%s",
href("%R/info?name=%h",zFwdTo), zFwdTo,
bFwdAdded ? " (not a direct descendant)" : "");
}
}
}else if( ridFwdTo ){
if( nd==0 ){
blob_reset(&desc);
blob_appendf(&desc,
"Check-in %z%h</a> only (%z%h</a> does not follow it)",
href("%R/info?name=%h",zBaseName), zBaseName,
href("%R/info?name=%h",zFwdTo), zFwdTo);
}else{
blob_appendf(&desc, " up to %z%h</a>%s",
href("%R/info?name=%h",zFwdTo), zFwdTo,
bFwdAdded ? " (not a direct descendant)":"");
}
}
if( advancedMenu ){
style_submenu_checkbox("v", "Files", (zType[0]!='a' && zType[0]!='c'),0);
}
style_submenu_entry("n","Max:",4,0);
timeline_y_submenu(1);
|
| ︙ | ︙ | |||
2813 2814 2815 2816 2817 2818 2819 |
zSearch, zSearch, zSearch);
}else{
blob_append_sql(&cond,
" AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')",
zSearch, zSearch);
}
}
| | | | | 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 |
zSearch, zSearch, zSearch);
}else{
blob_append_sql(&cond,
" AND (event.comment LIKE '%%%q%%' OR event.brief LIKE '%%%q%%')",
zSearch, zSearch);
}
}
rBefore = symbolic_name_to_mtime(zBefore, &zBefore, 1);
rAfter = symbolic_name_to_mtime(zAfter, &zAfter, 0);
rCirca = symbolic_name_to_mtime(zCirca, &zCirca, 0);
blob_append_sql(&sql, "%s", blob_sql_text(&cond));
if( rAfter>0.0 ){
if( rBefore>0.0 ){
blob_append_sql(&sql,
" AND event.mtime>=%.17g AND event.mtime<=%.17g\n"
" ORDER BY event.mtime ASC", rAfter-ONE_SECOND, rBefore+ONE_SECOND);
nEntry = -1;
|
| ︙ | ︙ | |||
2956 2957 2958 2959 2960 2961 2962 |
};
double rDate;
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
zDate = mprintf("%s", (zAfter ? zAfter : zBefore));
}
if( zDate ){
| | | | 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 |
};
double rDate;
zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
zDate = mprintf("%s", (zAfter ? zAfter : zBefore));
}
if( zDate ){
rDate = symbolic_name_to_mtime(zDate, 0, 0);
if( db_int(0,
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
" WHERE blob.rid=event.objid AND mtime<=%.17g%s)",
rDate-ONE_SECOND, blob_sql_text(&cond))
){
zOlderButton = fossil_strdup(url_render(&url, "b", zDate, "a", 0));
zOlderButtonLabel = "More";
}
free(zDate);
}
zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/");
if( (!zDate || !zDate[0]) && ( zAfter || zBefore ) ){
zDate = mprintf("%s", (zBefore ? zBefore : zAfter));
}
if( zDate ){
rDate = symbolic_name_to_mtime(zDate, 0, 0);
if( db_int(0,
"SELECT EXISTS (SELECT 1 FROM event CROSS JOIN blob"
" WHERE blob.rid=event.objid AND mtime>=%.17g%s)",
rDate+ONE_SECOND, blob_sql_text(&cond))
){
zNewerButton = fossil_strdup(url_render(&url, "a", zDate, "b", 0));
zNewerButtonLabel = "More";
|
| ︙ | ︙ | |||
3015 3016 3017 3018 3019 3020 3021 |
url_render(&url, "advm", "0", "udc", "1"));
}else{
style_submenu_element("Advanced", "%s",
url_render(&url, "advm", "1", "udc", "1"));
}
if( PB("showid") ) tmFlags |= TIMELINE_SHOWRID;
if( useDividers && zMark && zMark[0] ){
| | | 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 |
url_render(&url, "advm", "0", "udc", "1"));
}else{
style_submenu_element("Advanced", "%s",
url_render(&url, "advm", "1", "udc", "1"));
}
if( PB("showid") ) tmFlags |= TIMELINE_SHOWRID;
if( useDividers && zMark && zMark[0] ){
double r = symbolic_name_to_mtime(zMark, 0, 0);
if( r>0.0 && !selectedRid ) selectedRid = timeline_add_divider(r);
}
blob_zero(&sql);
if( PB("oldestfirst") ){
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby ASC /*scan*/");
}else{
db_prepare(&q, "SELECT * FROM timeline ORDER BY sortby DESC /*scan*/");
|
| ︙ | ︙ | |||
3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 |
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
fossil_print("+++ no more data (%d) +++\n", nEntry);
}
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
@ datetime(event.mtime,toLocal()) AS mDateTime,
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 |
fossil_print("+++ end of timeline (%d) +++\n", nEntry);
}else{
fossil_print("+++ no more data (%d) +++\n", nEntry);
}
}
if( fchngQueryInit ) db_finalize(&fchngQuery);
}
/*
** wiki_to_text(TEXT)
**
** Return a text rendering of Fossil-Wiki TEXT, intended for display
** on a timeline. The timeline-plaintext and timeline-hard-newlines
** settings are considered when doing this rendering.
*/
static void wiki_to_text_sqlfunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const char *zIn, *zOut;
int nIn, nOut;
Blob in, html, txt;
zIn = (const char*)sqlite3_value_text(argv[0]);
if( zIn==0 ) return;
nIn = sqlite3_value_bytes(argv[0]);
blob_init(&in, zIn, nIn);
blob_init(&html, 0, 0);
wiki_convert(&in, &html, wiki_convert_flags(0));
blob_reset(&in);
blob_init(&txt, 0, 0);
html_to_plaintext(blob_str(&html), &txt, 0);
blob_reset(&html);
nOut = blob_size(&txt);
zOut = blob_str(&txt);
while( fossil_isspace(zOut[0]) ){ zOut++; nOut--; }
while( nOut>0 && fossil_isspace(zOut[nOut-1]) ){ nOut--; }
sqlite3_result_text(context, zOut, nOut, SQLITE_TRANSIENT);
blob_reset(&txt);
}
/*
** Return a pointer to a static string that forms the basis for
** a timeline query for display on a TTY.
*/
const char *timeline_query_for_tty(void){
static int once = 0;
static const char zBaseSql[] =
@ SELECT
@ blob.rid AS rid,
@ uuid,
@ datetime(event.mtime,toLocal()) AS mDateTime,
@ wiki_to_text(coalesce(ecomment,comment))
@ || ' (user: ' || coalesce(euser,user,'?')
@ || (SELECT case when length(x)>0 then ' tags: ' || x else '' end
@ FROM (SELECT group_concat(substr(tagname,5), ', ') AS x
@ FROM tag, tagxref
@ WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid
@ AND tagxref.rid=blob.rid AND tagxref.tagtype>0))
@ || ')' as comment,
|
| ︙ | ︙ | |||
3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 |
@ FROM tag CROSS JOIN event CROSS JOIN blob
@ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
@ AND tagxref.tagtype>0
@ AND tagxref.rid=blob.rid
@ WHERE blob.rid=event.objid
@ AND tag.tagname='branch'
;
return zBaseSql;
}
/*
** Return true if the input string is a date in the ISO 8601 format:
** YYYY-MM-DD.
*/
| > > > > > | 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 |
@ FROM tag CROSS JOIN event CROSS JOIN blob
@ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid
@ AND tagxref.tagtype>0
@ AND tagxref.rid=blob.rid
@ WHERE blob.rid=event.objid
@ AND tag.tagname='branch'
;
if( !once && g.db ){
once = 1;
sqlite3_create_function(g.db, "wiki_to_text", 1, SQLITE_UTF8, 0,
wiki_to_text_sqlfunc, 0, 0);
}
return zBaseSql;
}
/*
** Return true if the input string is a date in the ISO 8601 format:
** YYYY-MM-DD.
*/
|
| ︙ | ︙ |
Changes to src/tkt.c.
| ︙ | ︙ | |||
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 |
}else{
showTimeline = 0;
}
}
if( !showTimeline && g.perm.Hyperlink ){
style_submenu_element("Timeline", "%R/info/%T", zUuid);
}
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br>\n", -1);
ticket_init();
initializeVariablesFromCGI();
getAllTicketFields();
initializeVariablesFromDb();
zScript = ticket_viewpage_code();
if( P("showfields")!=0 ) showAllFields();
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br>\n", -1);
safe_html_context(DOCSRC_TICKET);
Th_Render(zScript);
if( g.thTrace ) Th_Trace("END_TKTVIEW<br>\n", -1);
| > > > > > > < < < | 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
}else{
showTimeline = 0;
}
}
if( !showTimeline && g.perm.Hyperlink ){
style_submenu_element("Timeline", "%R/info/%T", zUuid);
}
zFullName = db_text(0,
"SELECT tkt_uuid FROM ticket"
" WHERE tkt_uuid GLOB '%q*'", zUuid);
if( g.perm.WrWiki && g.perm.WrTkt ){
style_submenu_element("Edit Description", "%R/wikiedit?name=ticket/%T", zFullName);
}
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW<br>\n", -1);
ticket_init();
initializeVariablesFromCGI();
getAllTicketFields();
initializeVariablesFromDb();
zScript = ticket_viewpage_code();
if( P("showfields")!=0 ) showAllFields();
if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW_SCRIPT<br>\n", -1);
safe_html_context(DOCSRC_TICKET);
Th_Render(zScript);
if( g.thTrace ) Th_Trace("END_TKTVIEW<br>\n", -1);
if( zFullName ){
attachment_list(zFullName, "<h2>Attachments:</h2>", 1);
}
style_finish_page();
}
|
| ︙ | ︙ |
Changes to src/tktsetup.c.
| ︙ | ︙ | |||
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
@ </td>
@ <th1>enable_output 1</th1>
@ </tr>
@ <tr><td class="tktDspLabel">Version Found In:</td>
@ <td colspan="3" valign="top" class="tktDspValue">
@ $<foundin>
@ </td></tr>
@
@ <th1>
@ if {[info exists comment]} {
@ if {[string length $comment]>10} {
@ html {
@ <tr><td class="tktDspLabel">Description:</td></tr>
@ <tr><td colspan="5" class="tktDspValue">
@ }
| > > > > > > | 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 |
@ </td>
@ <th1>enable_output 1</th1>
@ </tr>
@ <tr><td class="tktDspLabel">Version Found In:</td>
@ <td colspan="3" valign="top" class="tktDspValue">
@ $<foundin>
@ </td></tr>
@ </table>
@
@ <th1>
@ wiki_assoc "ticket" $tkt_uuid
@ </th1>
@
@ <table cellpadding="5" style="min-width:100%">
@ <th1>
@ if {[info exists comment]} {
@ if {[string length $comment]>10} {
@ html {
@ <tr><td class="tktDspLabel">Description:</td></tr>
@ <tr><td colspan="5" class="tktDspValue">
@ }
|
| ︙ | ︙ | |||
529 530 531 532 533 534 535 |
@ mimetype as xmimetype, icomment AS xcomment,
@ username AS xusername
@ FROM ticketchng
@ WHERE tkt_id=$tkt_id AND length(icomment)>0} {
@ if {$seenRow} {
@ html "<hr>\n"
@ } else {
| | | 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 |
@ mimetype as xmimetype, icomment AS xcomment,
@ username AS xusername
@ FROM ticketchng
@ WHERE tkt_id=$tkt_id AND length(icomment)>0} {
@ if {$seenRow} {
@ html "<hr>\n"
@ } else {
@ html "<tr><td class='tktDspLabel' style='text-align:left'>User Comments:</td></tr>\n"
@ html "<tr><td colspan='5' class='tktDspValue'>\n"
@ set seenRow 1
@ }
@ html "<span class='tktDspCommenter'>"
@ html "[htmlize $xlogin]"
@ if {$xlogin ne $xusername && [string length $xusername]>0} {
@ html " (claiming to be [htmlize $xusername])"
|
| ︙ | ︙ |
Changes to src/unversioned.c.
| ︙ | ︙ | |||
216 217 218 219 220 221 222 |
if( fossil_isspace(zName[0]) ) return 1;
zName++;
}
return 0;
}
/*
| | | | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
if( fossil_isspace(zName[0]) ) return 1;
zName++;
}
return 0;
}
/*
** COMMAND: uv# abbrv-subcom
** COMMAND: unversioned abbrv-subcom
**
** Usage: %fossil unversioned SUBCOMMAND ARGS...
** or: %fossil uv SUBCOMMAND ARGS..
**
** Unversioned files (UV-files) are artifacts that are synced and are available
** for download but which do not preserve history. Only the most recent version
** of each UV-file is retained. Changes to an UV-file are permanent and cannot
|
| ︙ | ︙ | |||
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 | ** revert ?URL? Restore the state of all unversioned files in the ** local repository to match the remote repository ** URL. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dry-run Show what would have happened ** ** remove|rm|delete FILE ... ** Remove unversioned files from the local repository. ** Changes are not pushed to other repositories until ** the next sync. ** ** Options: ** --glob PATTERN Remove files that match ** --like PATTERN Remove files that match ** ** sync ?URL? Synchronize the state of all unversioned files with ** the remote repository URL. The most recent version ** of each file is propagated to all repositories and ** all prior versions are permanently forgotten. ** The remote account requires the 'y' capability. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dry-run Show what would have happened ** ** touch FILE ... Update the TIMESTAMP on all of the listed files ** ** Options: ** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for the "add", ** "edit", "remove", and "touch" subcommands. ** -R|--repository REPO Use REPO as the repository | > > | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | ** revert ?URL? Restore the state of all unversioned files in the ** local repository to match the remote repository ** URL. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dry-run Show what would have happened ** --proxy PROXY Use the specified HTTP proxy ** ** remove|rm|delete FILE ... ** Remove unversioned files from the local repository. ** Changes are not pushed to other repositories until ** the next sync. ** ** Options: ** --glob PATTERN Remove files that match ** --like PATTERN Remove files that match ** ** sync ?URL? Synchronize the state of all unversioned files with ** the remote repository URL. The most recent version ** of each file is propagated to all repositories and ** all prior versions are permanently forgotten. ** The remote account requires the 'y' capability. ** ** Options: ** -v|--verbose Extra diagnostic output ** -n|--dry-run Show what would have happened ** --proxy PROXY Use the specified HTTP proxy ** ** touch FILE ... Update the TIMESTAMP on all of the listed files ** ** Options: ** --mtime TIMESTAMP Use TIMESTAMP instead of "now" for the "add", ** "edit", "remove", and "touch" subcommands. ** -R|--repository REPO Use REPO as the repository |
| ︙ | ︙ |
Changes to src/update.c.
| ︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 | ** --force-missing Force update if missing content after sync ** -K|--keep-merge-files On merge conflict, retain the temporary files ** used for merging, named *-baseline, *-original, ** and *-merge. ** --latest Acceptable in place of VERSION, update to ** latest version ** --nosync Do not auto-sync prior to update ** --setmtime Set timestamps of all files to match their ** SCM-side times (the timestamp of the last ** check-in which modified them). ** -v|--verbose Print status information about all files ** -W|--width WIDTH Width of lines (default is to auto-detect). ** Must be more than 20 or 0 (= no limit, ** resulting in a single line per entry). | > | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | ** --force-missing Force update if missing content after sync ** -K|--keep-merge-files On merge conflict, retain the temporary files ** used for merging, named *-baseline, *-original, ** and *-merge. ** --latest Acceptable in place of VERSION, update to ** latest version ** --nosync Do not auto-sync prior to update ** --proxy PROXY Use PROXY as http proxy during sync operation ** --setmtime Set timestamps of all files to match their ** SCM-side times (the timestamp of the last ** check-in which modified them). ** -v|--verbose Print status information about all files ** -W|--width WIDTH Width of lines (default is to auto-detect). ** Must be more than 20 or 0 (= no limit, ** resulting in a single line per entry). |
| ︙ | ︙ | |||
196 197 198 199 200 201 202 |
if( tid==0 || !is_a_version(tid) ){
fossil_fatal("no such check-in: %s", g.argv[2]);
}
}
}
/* If no VERSION is specified on the command-line, then look for a
| | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
if( tid==0 || !is_a_version(tid) ){
fossil_fatal("no such check-in: %s", g.argv[2]);
}
}
}
/* If no VERSION is specified on the command-line, then look for a
** descendant of the current version. If there are multiple descendants,
** look for one from the same branch as the current version. If there
** are still multiple descendants, show them all and refuse to update
** until the user selects one.
*/
if( tid==0 ){
int closeCode = 1;
compute_leaves(vid, closeCode);
|
| ︙ | ︙ |
Changes to src/user.c.
| ︙ | ︙ | |||
296 297 298 299 300 301 302 |
/*
** Prompt the user to enter a single line of text.
*/
void prompt_user(const char *zPrompt, Blob *pIn){
char *z;
char zLine[1000];
| | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
/*
** Prompt the user to enter a single line of text.
*/
void prompt_user(const char *zPrompt, Blob *pIn){
char *z;
char zLine[1000];
blob_init(pIn, 0, 0);
fossil_force_newline();
fossil_print("%s", zPrompt);
fflush(stdout);
z = fgets(zLine, sizeof(zLine), stdin);
if( z ){
int n = (int)strlen(z);
if( n>0 && z[n-1]=='\n' ) fossil_new_line_started();
|
| ︙ | ︙ | |||
329 330 331 332 333 334 335 | ** Query or set contact information for user USERNAME ** ** > fossil user default ?USERNAME? ** ** Query or set the default user. The default user is the ** user for command-line interaction. ** | | < | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | ** Query or set contact information for user USERNAME ** ** > fossil user default ?USERNAME? ** ** Query or set the default user. The default user is the ** user for command-line interaction. ** ** > fossil user list | ls ** ** List all users known to the repository ** ** > fossil user new ?USERNAME? ?CONTACT-INFO? ?PASSWORD? ** ** Create a new user in the repository. Users can never be ** deleted. They can be denied all access but they must continue |
| ︙ | ︙ |
Changes to src/utf8.c.
| ︙ | ︙ | |||
23 24 25 26 27 28 29 | #include "utf8.h" #include <sqlite3.h> #ifdef _WIN32 # include <windows.h> #endif #include "cygsup.h" | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#include "utf8.h"
#include <sqlite3.h>
#ifdef _WIN32
# include <windows.h>
#endif
#include "cygsup.h"
#if defined(_WIN32)
/*
** Translate MBCS to UTF-8. Return a pointer to the translated text.
** Call fossil_mbcs_free() to deallocate any memory used to store the
** returned pointer when done.
*/
char *fossil_mbcs_to_utf8(const char *zMbcs){
extern char *sqlite3_win32_mbcs_to_utf8(const char*);
|
| ︙ | ︙ |
Changes to src/util.c.
| ︙ | ︙ | |||
668 669 670 671 672 673 674 | ** not found. ** ** Search algorithm: ** (1) The local "editor" setting ** (2) The global "editor" setting ** (3) The VISUAL environment variable ** (4) The EDITOR environment variable | | > > > > > < | | < | > | | > | | 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 |
** not found.
**
** Search algorithm:
** (1) The local "editor" setting
** (2) The global "editor" setting
** (3) The VISUAL environment variable
** (4) The EDITOR environment variable
** (5) Any of the following programs that are available:
** notepad, nano, pico, jove, edit, vi, vim, ed,
*/
const char *fossil_text_editor(void){
const char *zEditor = db_get("editor", 0);
const char *azStdEd[] = {
"notepad", "nano", "pico", "jove", "edit", "vi", "vim", "ed"
};
int i = 0;
if( zEditor==0 ){
zEditor = fossil_getenv("VISUAL");
}
if( zEditor==0 ){
zEditor = fossil_getenv("EDITOR");
}
while( zEditor==0 && i<count(azStdEd) ){
if( fossil_app_on_path(azStdEd[i],0) ){
zEditor = azStdEd[i];
}else{
i++;
}
}
if( zEditor && is_false(zEditor) ) zEditor = 0;
return zEditor;
}
/*
** Construct a temporary filename.
**
** The returned string is obtained from sqlite3_malloc() and must be
|
| ︙ | ︙ | |||
893 894 895 896 897 898 899 |
*/
int fossil_num_digits(int n){
return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3
: n< 10000 ? 4 : n< 100000 ? 5 : n< 1000000 ? 6
: n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10;
}
| < < > > > | > > > > > > > > > > > > > > > > | > > > | | > > > > > > > > > > > > > | > > > > > > | > > | | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
*/
int fossil_num_digits(int n){
return n< 10 ? 1 : n< 100 ? 2 : n< 1000 ? 3
: n< 10000 ? 4 : n< 100000 ? 5 : n< 1000000 ? 6
: n<10000000 ? 7 : n<100000000 ? 8 : n<1000000000 ? 9 : 10;
}
/*
** Search for an executable on the PATH environment variable.
** Return true (1) if found and false (0) if not found.
**
** Print the full pathname of the first location if ePrint==1. Print
** all pathnames for the executable if ePrint==2 or more.
*/
int fossil_app_on_path(const char *zBinary, int ePrint){
const char *zPath = fossil_getenv("PATH");
char *zFull;
int i;
int bExists;
int bFound = 0;
while( zPath && zPath[0] ){
#ifdef _WIN32
while( zPath[0]==';' ) zPath++;
for(i=0; zPath[i] && zPath[i]!=';'; i++){}
zFull = mprintf("%.*s\\%s.exe", i, zPath, zBinary);
bExists = file_access(zFull, R_OK);
if( bExists!=0 ){
fossil_free(zFull);
zFull = mprintf("%.*s\\%s.bat", i, zPath, zBinary);
bExists = file_access(zFull, R_OK);
}
#else
while( zPath[0]==':' ) zPath++;
for(i=0; zPath[i] && zPath[i]!=':'; i++){}
zFull = mprintf("%.*s/%s", i, zPath, zBinary);
bExists = file_access(zFull, X_OK);
#endif
if( bExists==0 && ePrint ){
fossil_print("%s\n", zFull);
}
fossil_free(zFull);
if( bExists==0 ){
if( ePrint<2 ) return 1;
bFound = 1;
}
zPath += i;
}
return bFound;
}
/*
** COMMAND: which*
**
** Usage: fossil which [-a] NAME ...
**
** For each NAME mentioned as an argument, print the first location on the
** on PATH of the executable with that name. Or, show all locations on PATH
** for each argument if the -a option is used.
**
** This command is a substitute for the unix "which" command, which is not
** always available, especially on Windows.
*/
void test_app_on_path(void){
int i;
int ePrint = 1;
if( find_option("all","a",0)!=0 ) ePrint = 2;
verify_all_options();
for(i=2; i<g.argc; i++){
if( fossil_app_on_path(g.argv[i], ePrint)==0 ){
fossil_print("NOT FOUND: %s\n", g.argv[i]);
}
}
}
/*
** Return the name of a command that will launch a web-browser.
*/
const char *fossil_web_browser(void){
const char *zBrowser = 0;
#if defined(_WIN32)
zBrowser = db_get("web-browser", "start \"\"");
#elif defined(__DARWIN__) || defined(__APPLE__) || defined(__HAIKU__)
zBrowser = db_get("web-browser", "open");
#else
zBrowser = db_get("web-browser", 0);
if( zBrowser==0 ){
static const char *const azBrowserProg[] =
{ "xdg-open", "gnome-open", "firefox", "google-chrome" };
int i;
zBrowser = "echo";
for(i=0; i<count(azBrowserProg); i++){
if( fossil_app_on_path(azBrowserProg[i],0) ){
zBrowser = azBrowserProg[i];
break;
}
}
zBrowser = mprintf("%s 2>/dev/null", zBrowser);
}
#endif
|
| ︙ | ︙ |
Changes to src/wiki.c.
| ︙ | ︙ | |||
19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** This file contains code to do formatting of wiki text. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wiki.h" /* ** Return true if the input string is a well-formed wiki page name. ** ** Well-formed wiki page names do not begin or end with whitespace, ** and do not contain tabs or other control characters and do not ** contain more than a single space character in a row. Well-formed ** names must be between 1 and 100 characters in length, inclusive. | > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ** This file contains code to do formatting of wiki text. */ #include "config.h" #include <assert.h> #include <ctype.h> #include "wiki.h" #define has_prefix(literal_prfx, zStr) \ (fossil_strncmp((zStr), "" literal_prfx, (sizeof literal_prfx)-1)==0) /* ** Return true if the input string is a well-formed wiki page name. ** ** Well-formed wiki page names do not begin or end with whitespace, ** and do not contain tabs or other control characters and do not ** contain more than a single space character in a row. Well-formed ** names must be between 1 and 100 characters in length, inclusive. |
| ︙ | ︙ | |||
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
/* Return values from wiki_page_type() */
#if INTERFACE
# define WIKITYPE_UNKNOWN (-1)
# define WIKITYPE_NORMAL 0
# define WIKITYPE_BRANCH 1
# define WIKITYPE_CHECKIN 2
# define WIKITYPE_TAG 3
#endif
/*
** Figure out what type of wiki page we are dealing with.
*/
int wiki_page_type(const char *zPageName){
if( db_get_boolean("wiki-about",1)==0 ){
return WIKITYPE_NORMAL;
}else
| > | | | > > > > | 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
/* Return values from wiki_page_type() */
#if INTERFACE
# define WIKITYPE_UNKNOWN (-1)
# define WIKITYPE_NORMAL 0
# define WIKITYPE_BRANCH 1
# define WIKITYPE_CHECKIN 2
# define WIKITYPE_TAG 3
# define WIKITYPE_TICKET 4
#endif
/*
** Figure out what type of wiki page we are dealing with.
*/
int wiki_page_type(const char *zPageName){
if( db_get_boolean("wiki-about",1)==0 ){
return WIKITYPE_NORMAL;
}else
if( has_prefix("checkin/", zPageName)
&& db_exists("SELECT 1 FROM blob WHERE uuid=%Q",zPageName+8)
){
return WIKITYPE_CHECKIN;
}else
if( has_prefix("branch/", zPageName) ){
return WIKITYPE_BRANCH;
}else
if( has_prefix("tag/", zPageName) ){
return WIKITYPE_TAG;
}else
if( has_prefix("ticket/", zPageName) ){
return WIKITYPE_TICKET;
}
return WIKITYPE_NORMAL;
}
/*
** Returns a JSON-friendly string form of the integer value returned
** by wiki_page_type(zPageName).
*/
const char * wiki_page_type_name(const char *zPageName){
switch(wiki_page_type(zPageName)){
case WIKITYPE_CHECKIN: return "checkin";
case WIKITYPE_BRANCH: return "branch";
case WIKITYPE_TAG: return "tag";
case WIKITYPE_TICKET: return "ticket";
case WIKITYPE_NORMAL:
default: return "normal";
}
}
/*
** Add an appropriate style_header() for either the /wiki or /wikiedit page
|
| ︙ | ︙ | |||
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
cgi_redirectf("%R/timeline?t=%t",zPageName);
}else{
style_header("Notes About Tag %h", zPageName);
style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName);
}
break;
}
}
return eType;
}
/*
** Wiki pages with special names "branch/...", "checkin/...", and "tag/..."
** requires perm.Write privilege in addition to perm.WrWiki in order
** to write. This function determines whether the extra perm.Write
** is required and available. Return true if writing to the wiki page
** may proceed, and return false if permission is lacking.
*/
static int wiki_special_permission(const char *zPageName){
if( strncmp(zPageName,"branch/",7)!=0
&& strncmp(zPageName,"checkin/",8)!=0
&& strncmp(zPageName,"tag/",4)!=0
){
return 1;
}
if( db_get_boolean("wiki-about",1)==0 ){
return 1;
}
return g.perm.Write;
}
/*
** WEBPAGE: wiki
**
| > > > > > > > > > > > > > > | 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 |
cgi_redirectf("%R/timeline?t=%t",zPageName);
}else{
style_header("Notes About Tag %h", zPageName);
style_submenu_element("Tag Timeline","%R/timeline?t=%t",zPageName);
}
break;
}
case WIKITYPE_TICKET: {
zPageName += 7;
if( zExtra[0]==0 && !P("p") ){
cgi_redirectf("%R/tktview/%s",zPageName);
}else{
style_header("Notes About Ticket %h", zPageName);
style_submenu_element("Ticket","%R/tktview/%s",zPageName);
}
break;
}
}
return eType;
}
/*
** Wiki pages with special names "branch/...", "checkin/...", and "tag/..."
** requires perm.Write privilege in addition to perm.WrWiki in order
** to write. This function determines whether the extra perm.Write
** is required and available. Return true if writing to the wiki page
** may proceed, and return false if permission is lacking.
*/
static int wiki_special_permission(const char *zPageName){
if( strncmp(zPageName,"branch/",7)!=0
&& strncmp(zPageName,"checkin/",8)!=0
&& strncmp(zPageName,"tag/",4)!=0
&& strncmp(zPageName,"ticket/",7)!=0
){
return 1;
}
if( db_get_boolean("wiki-about",1)==0 ){
return 1;
}
if( strncmp(zPageName,"ticket/",7)==0 ){
return g.perm.WrTkt;
}
return g.perm.Write;
}
/*
** WEBPAGE: wiki
**
|
| ︙ | ︙ | |||
1966 1967 1968 1969 1970 1971 1972 |
style_submenu_element("Active", "%R/wcontent");
}else{
style_submenu_element("All", "%R/wcontent?all=1");
}
cgi_check_for_malice();
showCkBr = db_exists(
"SELECT tag.tagname AS tn FROM tag JOIN tagxref USING(tagid) "
| | > | 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 |
style_submenu_element("Active", "%R/wcontent");
}else{
style_submenu_element("All", "%R/wcontent?all=1");
}
cgi_check_for_malice();
showCkBr = db_exists(
"SELECT tag.tagname AS tn FROM tag JOIN tagxref USING(tagid) "
"WHERE ( tn GLOB 'wiki-checkin/*' OR tn GLOB 'wiki-branch/*' OR "
" tn GLOB 'wiki-tag/*' OR tn GLOB 'wiki-ticket/*' ) "
" AND TYPEOF(tagxref.value+0)='integer'" );
if( showCkBr ){
showCkBr = P("showckbr")!=0;
style_submenu_checkbox("showckbr", "Show associated wikis", 0, 0);
}
wiki_standard_submenu(W_ALL_BUT(W_LIST));
db_prepare(&q, listAllWikiPages/*works-like:""*/);
|
| ︙ | ︙ | |||
1996 1997 1998 1999 2000 2001 2002 |
double rWmtime = db_column_double(&q, 3);
sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0);
char *zAge;
int wcnt = db_column_int(&q, 4);
char *zWDisplayName;
if( !showCkBr &&
| | | > > | | | 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 |
double rWmtime = db_column_double(&q, 3);
sqlite3_int64 iMtime = (sqlite3_int64)(rWmtime*86400.0);
char *zAge;
int wcnt = db_column_int(&q, 4);
char *zWDisplayName;
if( !showCkBr &&
(has_prefix("checkin/", zWName) ||
has_prefix("branch/", zWName) ||
has_prefix("tag/", zWName) ||
has_prefix("ticket/", zWName) )){
continue;
}
if( has_prefix("checkin/",zWName) || has_prefix("ticket/",zWName) ){
zWDisplayName = mprintf("%.25s...", zWName);
}else{
zWDisplayName = fossil_strdup(zWName);
}
if( wrid==0 ){
if( !showAll ) continue;
@ <tr><td data-sortkey="%h(zSort)">\
@ %z(href("%R/whistory?name=%T",zWName))<s>%h(zWDisplayName)</s></a></td>
}else{
@ <tr><td data-sortkey="%h(zSort)">\
|
| ︙ | ︙ | |||
2499 2500 2501 2502 2503 2504 2505 |
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
const int wrid = db_column_int(&q, 2);
if(!showAll && !wrid){
continue;
}
if( !showCkBr &&
| | | > > | 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 |
while( db_step(&q)==SQLITE_ROW ){
const char *zName = db_column_text(&q, 0);
const int wrid = db_column_int(&q, 2);
if(!showAll && !wrid){
continue;
}
if( !showCkBr &&
(has_prefix("checkin/", zName) ||
has_prefix("branch/", zName) ||
has_prefix("tag/", zName) ||
has_prefix("ticket/", zName) ) ){
continue;
}
if( showIds ){
const char *zUuid = db_column_text(&q, 1);
fossil_print("%s ",zUuid);
}
fossil_print( "%s\n",zName);
|
| ︙ | ︙ | |||
2549 2550 2551 2552 2553 2554 2555 |
@ <div class="section accordion">About %s(zPrefix) %h(zName)</div>
}
}
/*
** Add an "Wiki" button in a submenu that links to the read-wiki page.
*/
| | | > > > > > > > > > > > > > | | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 |
@ <div class="section accordion">About %s(zPrefix) %h(zName)</div>
}
}
/*
** Add an "Wiki" button in a submenu that links to the read-wiki page.
*/
static void wiki_submenu_to_read_wiki(
const char *zPrefix, /* "branch", "tag", or "checkin" */
const char *zName, /* Name of the object */
unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
){
if( g.perm.RdWiki && (mFlags & WIKIASSOC_MENU_READ)!=0 ){
style_submenu_element("Wiki", "%R/wiki?name=%s/%t", zPrefix, zName);
}
}
/*
** Add an "Edit Wiki" button in a submenu that links to the edit-wiki page.
*/
static void wiki_submenu_to_edit_wiki(
const char *zPrefix, /* "branch", "tag", or "checkin" */
const char *zName, /* Name of the object */
unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
){
if( g.perm.WrWiki && (mFlags & WIKIASSOC_MENU_WRITE)!=0 ){
style_submenu_element("Edit Wiki", "%R/wikiedit?name=%s/%t", zPrefix, zName);
}
}
/*
** Check to see if there exists a wiki page with a name zPrefix/zName.
** If there is, then render a <div class='section'>..</div> and
** return true.
**
** If there is no such wiki page, return false.
*/
int wiki_render_associated(
const char *zPrefix, /* "branch", "tag", "ticket", or "checkin" */
const char *zName, /* Name of the object */
unsigned int mFlags /* Zero or more WIKIASSOC_* flags */
){
int rid;
Manifest *pWiki;
if( !db_get_boolean("wiki-about",1) ) return 0;
rid = db_int(0,
|
| ︙ | ︙ | |||
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 |
blob_init(&markdown, pWiki->zWiki, -1);
markdown_to_html(&markdown, &title, &tail);
if( blob_size(&title) ){
@ <div class="section accordion">%h(blob_str(&title))</div>
}else{
wiki_section_label(zPrefix, zName, mFlags);
}
wiki_submenu_to_edit_wiki(zPrefix, zName, mFlags);
@ <div class="accordion_panel">
safe_html_context(DOCSRC_WIKI);
safe_html(&tail);
convert_href_and_output(&tail);
@ </div>
blob_reset(&tail);
| > | 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 |
blob_init(&markdown, pWiki->zWiki, -1);
markdown_to_html(&markdown, &title, &tail);
if( blob_size(&title) ){
@ <div class="section accordion">%h(blob_str(&title))</div>
}else{
wiki_section_label(zPrefix, zName, mFlags);
}
wiki_submenu_to_read_wiki(zPrefix, zName, mFlags);
wiki_submenu_to_edit_wiki(zPrefix, zName, mFlags);
@ <div class="accordion_panel">
safe_html_context(DOCSRC_WIKI);
safe_html(&tail);
convert_href_and_output(&tail);
@ </div>
blob_reset(&tail);
|
| ︙ | ︙ |
Changes to src/wikiformat.c.
| ︙ | ︙ | |||
21 22 23 24 25 26 27 | #include <assert.h> #include "wikiformat.h" #if INTERFACE /* ** Allowed wiki transformation operations */ | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <assert.h>
#include "wikiformat.h"
#if INTERFACE
/*
** Allowed wiki transformation operations
*/
#define WIKI_HTMLONLY 0x0001 /* HTML markup only. No wiki */
#define WIKI_INLINE 0x0002 /* Do not surround with <p>..</p> */
/* avalable for reuse: 0x0004 --- formerly WIKI_NOBLOCK */
#define WIKI_BUTTONS 0x0008 /* Allow sub-menu buttons */
#define WIKI_NOBADLINKS 0x0010 /* Ignore broken hyperlinks */
#define WIKI_LINKSONLY 0x0020 /* No markup. Only decorate links */
#define WIKI_NEWLINE 0x0040 /* Honor \n - break lines at each \n */
#define WIKI_MARKDOWNLINKS 0x0080 /* Resolve hyperlinks as in markdown */
#define WIKI_SAFE 0x0100 /* Make the result safe for embedding */
#define WIKI_TARGET_BLANK 0x0200 /* Hyperlinks go to a new window */
#define WIKI_NOBRACKET 0x0400 /* Omit extra [..] around hyperlinks */
#define WIKI_ADMIN 0x0800 /* Ignore g.perm.Hyperlink */
#define WIKI_MARK 0x1000 /* Add <mark>..</mark> around problems */
/*
** Return values from wiki_convert
*/
#define RENDER_LINK 0x0001 /* One or more hyperlinks rendered */
#define RENDER_ENTITY 0x0002 /* One or more HTML entities (ex: <) */
#define RENDER_TAG 0x0004 /* One or more HTML tags */
#define RENDER_BLOCKTAG 0x0008 /* One or more HTML block tags (ex: <p>) */
#define RENDER_BLOCK 0x0010 /* Block wiki (paragraphs, etc.) */
#define RENDER_MARK 0x0020 /* Output contains <mark>..</mark> */
#define RENDER_BADLINK 0x0100 /* Bad hyperlink syntax seen */
#define RENDER_BADTARGET 0x0200 /* Bad hyperlink target */
#define RENDER_BADTAG 0x0400 /* Bad HTML tag or tag syntax */
#define RENDER_BADENTITY 0x0800 /* Bad HTML entity syntax */
#define RENDER_BADHTML 0x1000 /* Bad HTML seen */
#define RENDER_ERROR 0x8000 /* Some other kind of error */
/* Composite values: */
#define RENDER_ANYERROR 0x9f00 /* Mask for any kind of error */
#endif /* INTERFACE */
/*
** These are the only markup attributes allowed.
*/
enum allowed_attr_t {
ATTR_ALIGN = 1,
|
| ︙ | ︙ | |||
442 443 444 445 446 447 448 | ** State flags. Save the lower 16 bits for the WIKI_* flags. */ #define AT_NEWLINE 0x0010000 /* At start of a line */ #define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */ #define ALLOW_WIKI 0x0040000 /* Allow wiki markup */ #define ALLOW_LINKS 0x0080000 /* Allow [...] hyperlinks */ #define FONT_MARKUP_ONLY 0x0100000 /* Only allow MUTYPE_FONT markup */ | < | > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 |
** State flags. Save the lower 16 bits for the WIKI_* flags.
*/
#define AT_NEWLINE 0x0010000 /* At start of a line */
#define AT_PARAGRAPH 0x0020000 /* At start of a paragraph */
#define ALLOW_WIKI 0x0040000 /* Allow wiki markup */
#define ALLOW_LINKS 0x0080000 /* Allow [...] hyperlinks */
#define FONT_MARKUP_ONLY 0x0100000 /* Only allow MUTYPE_FONT markup */
#define IN_LIST 0x0200000 /* Within wiki <ul> or <ol> */
/*
** Current state of the rendering engine
*/
typedef struct Renderer Renderer;
struct Renderer {
Blob *pOut; /* Output appended to this blob */
int state; /* Flag that govern rendering */
int mRender; /* Mask of RENDER_* values to return */
unsigned renderFlags; /* Flags from the client */
int wikiList; /* Current wiki list type */
int inVerbatim; /* True in <verbatim> mode */
int preVerbState; /* Value of state prior to verbatim */
int wantAutoParagraph; /* True if a <p> is desired */
int inAutoParagraph; /* True if within an automatic paragraph */
int pikchrHtmlFlags; /* Flags for pikchr_to_html() */
|
| ︙ | ︙ | |||
677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
** characters in that token. Write the token type into *pTokenType.
*/
static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
int n;
if( z[0]=='<' ){
n = html_tag_length(z);
if( n>0 ){
*pTokenType = TOKEN_MARKUP;
return n;
}else{
*pTokenType = TOKEN_CHARACTER;
return 1;
}
}
| > > > > > > > > > < < < < | 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
** characters in that token. Write the token type into *pTokenType.
*/
static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
int n;
if( z[0]=='<' ){
n = html_tag_length(z);
if( n>0 ){
p->mRender |= RENDER_TAG;
*pTokenType = TOKEN_MARKUP;
return n;
}else{
p->mRender |= RENDER_BADTAG;
*pTokenType = TOKEN_CHARACTER;
return 1;
}
}
if( z[0]=='&' ){
p->mRender |= RENDER_ENTITY;
if( (p->inVerbatim || !isElement(z)) ){
*pTokenType = TOKEN_CHARACTER;
return 1;
}
}
if( (p->state & ALLOW_WIKI)!=0 ){
if( z[0]=='\n' ){
n = paragraphBreakLength(z);
if( n>0 ){
*pTokenType = TOKEN_PARAGRAPH;
return n;
}else{
|
| ︙ | ︙ | |||
723 724 725 726 727 728 729 |
if( (p->state & AT_PARAGRAPH)!=0 && fossil_isspace(z[0]) ){
n = indentLength(z);
if( n>0 ){
*pTokenType = TOKEN_INDENT;
return n;
}
}
| | > | | > > > > > | > | > | | > > > > > > | > | | > > > > > > | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 |
if( (p->state & AT_PARAGRAPH)!=0 && fossil_isspace(z[0]) ){
n = indentLength(z);
if( n>0 ){
*pTokenType = TOKEN_INDENT;
return n;
}
}
if( z[0]=='[' ){
if( (n = linkLength(z))>0 ){
*pTokenType = TOKEN_LINK;
return n;
}else if( p->state & WIKI_MARK ){
blob_append_string(p->pOut, "<mark>");
p->mRender |= RENDER_BADLINK|RENDER_MARK;
}else{
p->mRender |= RENDER_BADLINK;
}
}
}else if( (p->state & ALLOW_LINKS)!=0 && z[0]=='[' ){
if( (n = linkLength(z))>0 ){
*pTokenType = TOKEN_LINK;
return n;
}else if( p->state & WIKI_MARK ){
blob_append_string(p->pOut, "<mark>");
p->mRender |= RENDER_BADLINK|RENDER_MARK;
}else{
p->mRender |= RENDER_BADLINK;
}
}
*pTokenType = TOKEN_TEXT;
return 1 + textLength(z+1, p->state);
}
/*
** Parse only Wiki links, return everything else as TOKEN_RAW.
**
** z points to the start of a token. Return the number of
** characters in that token. Write the token type into *pTokenType.
*/
static int nextRawToken(const char *z, Renderer *p, int *pTokenType){
int n;
if( z[0]=='[' ){
if( (n = linkLength(z))>0 ){
*pTokenType = TOKEN_LINK;
return n;
}else if( p->state & WIKI_MARK ){
blob_append_string(p->pOut, "<mark>");
p->mRender |= RENDER_BADLINK|RENDER_MARK;
}else{
p->mRender |= RENDER_BADLINK;
}
}
*pTokenType = TOKEN_RAW;
return 1 + textLength(z+1, p->state);
}
/*
** A single markup is parsed into an instance of the following
|
| ︙ | ︙ | |||
1246 1247 1248 1249 1250 1251 1252 1253 | ** ** [WikiPageName] ** [wiki:WikiPageName] ** ** [2010-02-27 07:13] ** ** [InterMap:Link] -> Interwiki link */ | > > > > | > | 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 |
**
** [WikiPageName]
** [wiki:WikiPageName]
**
** [2010-02-27 07:13]
**
** [InterMap:Link] -> Interwiki link
**
** The return value is a mask of RENDER_* values indicating what happened.
** Probably the return value is 0 on success and RENDER_BADTARGET or
** RENDER_BADLINK if there are problems.
*/
int wiki_resolve_hyperlink(
Blob *pOut, /* Write the HTML output here */
int mFlags, /* Rendering option flags */
const char *zTarget, /* Hyperlink target; text within [...] */
char *zClose, /* Write hyperlink closing text here */
int nClose, /* Bytes available in zClose[] */
const char *zOrig, /* Complete document text */
const char *zTitle /* Title of the link */
){
const char *zTerm = "</a>";
const char *z;
char *zExtra = 0;
const char *zExtraNS = 0;
char *zRemote = 0;
int rc = 0;
if( zTitle ){
zExtra = mprintf(" title='%h'", zTitle);
zExtraNS = zExtra+1;
}else if( mFlags & WIKI_TARGET_BLANK ){
zExtra = mprintf(" target='_blank'");
zExtraNS = zExtra+1;
|
| ︙ | ︙ | |||
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 |
blob_appendf(pOut, "%s", zLB);
zTerm = "]";
}
}
}else if( !in_this_repo(zTarget) ){
if( (mFlags & (WIKI_LINKSONLY|WIKI_NOBADLINKS))!=0 ){
zTerm = "";
}else{
blob_appendf(pOut, "<span class=\"brokenlink\">%s", zLB);
zTerm = "]</span>";
}
| > > > > > | | > > > > > > > > > > > > > > > > > > > > > | 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 |
blob_appendf(pOut, "%s", zLB);
zTerm = "]";
}
}
}else if( !in_this_repo(zTarget) ){
if( (mFlags & (WIKI_LINKSONLY|WIKI_NOBADLINKS))!=0 ){
zTerm = "";
}else if( (mFlags & WIKI_MARK)!=0 ){
blob_appendf(pOut, "<mark>%s", zLB);
zTerm = "]</mark>";
rc |= RENDER_MARK;
}else{
blob_appendf(pOut, "<span class=\"brokenlink\">%s", zLB);
zTerm = "]</span>";
}
rc |= RENDER_BADTARGET;
}else if( g.perm.Hyperlink || (mFlags & WIKI_ADMIN)!=0 ){
blob_appendf(pOut, "%z%s",xhref(zExtraNS, "%R/info/%s", zTarget), zLB);
zTerm = "]</a>";
}else{
zTerm = "";
}
if( zTerm[0]==']' && (mFlags & WIKI_NOBRACKET)!=0 ) zTerm++;
}else if( (zRemote = interwiki_url(zTarget))!=0 ){
blob_appendf(pOut, "<a href=\"%z\"%s>", zRemote, zExtra);
zTerm = "</a>";
}else if( (z = validWikiPageName(mFlags, zTarget))!=0 ){
/* The link is to a valid wiki page name */
const char *zOverride = wiki_is_overridden(zTarget);
if( zOverride ){
blob_appendf(pOut, "<a href=\"%R/info/%S\"%s>", zOverride, zExtra);
}else{
blob_appendf(pOut, "<a href=\"%R/wiki?name=%T\"%s>", z, zExtra);
}
}else if( strlen(zTarget)>=10 && fossil_isdigit(zTarget[0]) && zTarget[4]=='-'
&& db_int(0, "SELECT datetime(%Q) NOT NULL", zTarget) ){
/* Dates or date-and-times in ISO8601 resolve to a link to the
** timeline for that date */
blob_appendf(pOut, "<a href=\"%R/timeline?c=%T\"%s>", zTarget, zExtra);
}else if( mFlags & WIKI_MARKDOWNLINKS ){
/* If none of the above, and if rendering links for markdown, then
** create a link to the literal text of the target */
blob_appendf(pOut, "<a href=\"%h\"%s>", zTarget, zExtra);
}else if( mFlags & WIKI_MARK ){
blob_appendf(pOut, "<mark>[");
zTerm = "]</mark>";
rc |= RENDER_BADTARGET|RENDER_MARK;
}else if( zOrig && zTarget>=&zOrig[2]
&& zTarget[-1]=='[' && !fossil_isspace(zTarget[-2]) ){
/* If the hyperlink markup is not preceded by whitespace, then it
** is probably a C-language subscript or similar, not really a
** hyperlink. Just ignore it. */
zTerm = "";
}else if( (mFlags & (WIKI_NOBADLINKS|WIKI_LINKSONLY))!=0 ){
/* Also ignore the link if various flags are set */
zTerm = "";
rc |= RENDER_BADTARGET;
}else{
blob_appendf(pOut, "<span class=\"brokenlink\">[%h]", zTarget);
zTerm = "</span>";
rc |= RENDER_BADTARGET;
}
if( zExtra ) fossil_free(zExtra);
assert( (int)strlen(zTerm)<nClose );
sqlite3_snprintf(nClose, zClose, "%s", zTerm);
return rc;
}
/*
** Check zTarget to see if it looks like a valid hyperlink target.
** Return true if it does seem valid and false if not.
*/
int wiki_valid_link_target(char *zTarget){
char zClose[30];
Blob notUsed;
blob_init(¬Used, 0, 0);
wiki_resolve_hyperlink(¬Used, WIKI_NOBADLINKS|WIKI_ADMIN,
zTarget, zClose, sizeof(zClose)-1, 0, 0);
blob_reset(¬Used);
return zClose[0]!=0;
}
/*
** Check to see if the given parsed markup is the correct
** </verbatim> tag.
*/
static int endVerbatim(Renderer *p, ParsedMarkup *pMarkup){
|
| ︙ | ︙ | |||
1448 1449 1450 1451 1452 1453 1454 |
**
** This routine will probably modify the content of z[].
*/
static void wiki_render(Renderer *p, char *z){
int tokenType;
ParsedMarkup markup;
int n;
| < < < < < | | | | | | | < | < < | | | | | | | | | | | | | < < | < | | | | | | | | | | | | | < | < < | | | | | | | | | | | | | < < > | | | | | < > > > > > > > > > > > > > > > > | | 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 |
**
** This routine will probably modify the content of z[].
*/
static void wiki_render(Renderer *p, char *z){
int tokenType;
ParsedMarkup markup;
int n;
int wikiHtmlOnly = (p->state & (WIKI_HTMLONLY | WIKI_LINKSONLY))!=0;
int linksOnly = (p->state & WIKI_LINKSONLY)!=0;
char *zOrig = z;
/* Make sure the attribute constants and names still align
** following changes in the attribute list. */
assert( fossil_strcmp(aAttribute[ATTR_WIDTH].zName, "width")==0 );
while( z[0] ){
if( wikiHtmlOnly ){
n = nextRawToken(z, p, &tokenType);
}else{
n = nextWikiToken(z, p, &tokenType);
}
p->state &= ~(AT_NEWLINE|AT_PARAGRAPH);
switch( tokenType ){
case TOKEN_PARAGRAPH: {
if( p->wikiList ){
popStackToTag(p, p->wikiList);
p->wikiList = 0;
}
endAutoParagraph(p);
blob_append_string(p->pOut, "\n\n");
p->wantAutoParagraph = 1;
p->state |= AT_PARAGRAPH|AT_NEWLINE;
break;
}
case TOKEN_NEWLINE: {
if( p->renderFlags & WIKI_NEWLINE ){
blob_append_string(p->pOut, "<br>\n");
}else{
blob_append_string(p->pOut, "\n");
}
p->state |= AT_NEWLINE;
break;
}
case TOKEN_BUL_LI: {
p->mRender |= RENDER_BLOCK;
if( p->wikiList!=MARKUP_UL ){
if( p->wikiList ){
popStackToTag(p, p->wikiList);
}
endAutoParagraph(p);
pushStack(p, MARKUP_UL);
blob_append_string(p->pOut, "<ul>");
p->wikiList = MARKUP_UL;
}
popStackToTag(p, MARKUP_LI);
startAutoParagraph(p);
pushStack(p, MARKUP_LI);
blob_append_string(p->pOut, "<li>");
break;
}
case TOKEN_NUM_LI: {
p->mRender |= RENDER_BLOCK;
if( p->wikiList!=MARKUP_OL ){
if( p->wikiList ){
popStackToTag(p, p->wikiList);
}
endAutoParagraph(p);
pushStack(p, MARKUP_OL);
blob_append_string(p->pOut, "<ol>");
p->wikiList = MARKUP_OL;
}
popStackToTag(p, MARKUP_LI);
startAutoParagraph(p);
pushStack(p, MARKUP_LI);
blob_append_string(p->pOut, "<li>");
break;
}
case TOKEN_ENUM: {
p->mRender |= RENDER_BLOCK;
if( p->wikiList!=MARKUP_OL ){
if( p->wikiList ){
popStackToTag(p, p->wikiList);
}
endAutoParagraph(p);
pushStack(p, MARKUP_OL);
blob_append_string(p->pOut, "<ol>");
p->wikiList = MARKUP_OL;
}
popStackToTag(p, MARKUP_LI);
startAutoParagraph(p);
pushStack(p, MARKUP_LI);
blob_appendf(p->pOut, "<li value=\"%d\">", atoi(z));
break;
}
case TOKEN_INDENT: {
p->mRender |= RENDER_BLOCK;
assert( p->wikiList==0 );
pushStack(p, MARKUP_BLOCKQUOTE);
blob_append_string(p->pOut, "<blockquote>");
p->wantAutoParagraph = 0;
p->wikiList = MARKUP_BLOCKQUOTE;
break;
}
case TOKEN_CHARACTER: {
startAutoParagraph(p);
if( p->state & WIKI_MARK ){
blob_append_string(p->pOut, "<mark>");
p->mRender |= RENDER_MARK;
}
if( z[0]=='<' ){
p->mRender |= RENDER_BADTAG;
blob_append_string(p->pOut, "<");
}else if( z[0]=='&' ){
p->mRender |= RENDER_BADENTITY;
blob_append_string(p->pOut, "&");
}
if( p->state & WIKI_MARK ){
if( fossil_isalnum(z[1]) || (z[1]=='/' && fossil_isalnum(z[2])) ){
int kk;
for(kk=2; fossil_isalnum(z[kk]); kk++){}
blob_append(p->pOut, &z[1], kk-1);
n = kk;
}
blob_append_string(p->pOut, "</mark>");
}
break;
}
case TOKEN_LINK: {
char *zTarget;
char *zDisplay = 0;
int i, j;
int savedState;
char zClose[20];
char cS1 = 0;
int iS1 = 0;
startAutoParagraph(p);
p->mRender |= RENDER_LINK;
zTarget = &z[1];
for(i=1; z[i] && z[i]!=']'; i++){
if( z[i]=='|' && zDisplay==0 ){
zDisplay = &z[i+1];
for(j=i; j>0 && fossil_isspace(z[j-1]); j--){}
iS1 = j;
cS1 = z[j];
z[j] = 0;
}
}
z[i] = 0;
if( zDisplay==0 ){
zDisplay = zTarget + interwiki_removable_prefix(zTarget);
}else{
while( fossil_isspace(*zDisplay) ) zDisplay++;
}
p->mRender |= wiki_resolve_hyperlink(p->pOut, p->state,
zTarget, zClose, sizeof(zClose), zOrig, 0);
if( linksOnly || zClose[0]==0 || p->inVerbatim ){
if( cS1 ) z[iS1] = cS1;
if( zClose[0]!=']' ){
blob_appendf(p->pOut, "[%h]%s", zTarget, zClose);
}else{
blob_appendf(p->pOut, "%h%s", zTarget, zClose);
|
| ︙ | ︙ | |||
1685 1686 1687 1688 1689 1690 1691 1692 1693 |
}
}else
/* Render invalid markup literally. The markup appears in the
** final output as plain text.
*/
if( markup.iCode==MARKUP_INVALID ){
unparseMarkup(&markup);
startAutoParagraph(p);
| > > > > > > > | < > > < < < < < < | 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 |
}
}else
/* Render invalid markup literally. The markup appears in the
** final output as plain text.
*/
if( markup.iCode==MARKUP_INVALID ){
p->mRender |= RENDER_BADTAG;
unparseMarkup(&markup);
startAutoParagraph(p);
if( p->state & WIKI_MARK ){
p->mRender |= RENDER_MARK;
blob_append_string(p->pOut, "<mark>");
htmlize_to_blob(p->pOut, z, n);
blob_append_string(p->pOut, "</mark>");
}else{
blob_append_string(p->pOut, "<");
htmlize_to_blob(p->pOut, z+1, n-1);
}
}else
/* If the markup is not font-change markup ignore it if the
** font-change-only flag is set.
*/
if( (markup.iType&MUTYPE_FONT)==0 && (p->state & FONT_MARKUP_ONLY)!=0 ){
/* Do nothing */
}else
if( markup.iCode==MARKUP_NOWIKI ){
if( markup.endTag ){
p->state |= ALLOW_WIKI;
}else{
p->state &= ~ALLOW_WIKI;
}
}else
/* Generate end-tags */
if( markup.endTag ){
popStackToTag(p, markup.iCode);
}else
/* Push <div> markup onto the stack together with the id=ID attribute.
*/
|
| ︙ | ︙ | |||
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 |
pushStack(p, markup.iCode);
}
}else
{
if( markup.iType==MUTYPE_FONT ){
startAutoParagraph(p);
}else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){
p->wantAutoParagraph = 0;
}
if( markup.iCode==MARKUP_HR
|| markup.iCode==MARKUP_H1
|| markup.iCode==MARKUP_H2
|| markup.iCode==MARKUP_H3
|| markup.iCode==MARKUP_H4
| > | 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 |
pushStack(p, markup.iCode);
}
}else
{
if( markup.iType==MUTYPE_FONT ){
startAutoParagraph(p);
}else if( markup.iType==MUTYPE_BLOCK || markup.iType==MUTYPE_LIST ){
p->mRender |= RENDER_BLOCKTAG;
p->wantAutoParagraph = 0;
}
if( markup.iCode==MARKUP_HR
|| markup.iCode==MARKUP_H1
|| markup.iCode==MARKUP_H2
|| markup.iCode==MARKUP_H3
|| markup.iCode==MARKUP_H4
|
| ︙ | ︙ | |||
1827 1828 1829 1830 1831 1832 1833 1834 | /* ** Transform the text in the pIn blob. Write the results ** into the pOut blob. The pOut blob should already be ** initialized. The output is merely appended to pOut. ** If pOut is NULL, then the output is appended to the CGI ** reply. */ | > > | | 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 |
/*
** Transform the text in the pIn blob. Write the results
** into the pOut blob. The pOut blob should already be
** initialized. The output is merely appended to pOut.
** If pOut is NULL, then the output is appended to the CGI
** reply.
**
** Return a mask of RENDER_ flags indicating what happened.
*/
int wiki_convert(Blob *pIn, Blob *pOut, int flags){
Renderer renderer;
memset(&renderer, 0, sizeof(renderer));
renderer.renderFlags = flags;
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH|flags;
if( flags & WIKI_INLINE ){
renderer.wantAutoParagraph = 0;
|
| ︙ | ︙ | |||
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 |
wiki_render(&renderer, blob_str(pIn));
endAutoParagraph(&renderer);
while( renderer.nStack ){
popStack(&renderer);
}
blob_append_char(renderer.pOut, '\n');
free(renderer.aStack);
}
/*
** COMMAND: test-wiki-render
**
** Usage: %fossil test-wiki-render FILE [OPTIONS]
**
** Translate the input FILE from Fossil-wiki into HTML and write
** the resulting HTML on standard output.
**
** Options:
** --buttons Set the WIKI_BUTTONS flag
** --htmlonly Set the WIKI_HTMLONLY flag
** --linksonly Set the WIKI_LINKSONLY flag
** --nobadlinks Set the WIKI_NOBADLINKS flag
| > > > > > > | | < > > > > > | > > > > | > > > | > | > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > | | > | > > > > > > > > | 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 |
wiki_render(&renderer, blob_str(pIn));
endAutoParagraph(&renderer);
while( renderer.nStack ){
popStack(&renderer);
}
blob_append_char(renderer.pOut, '\n');
free(renderer.aStack);
return renderer.mRender;
}
/*
** COMMAND: test-wiki-render
**
** Usage: %fossil test-wiki-render FILE [OPTIONS]
**
** Translate the input FILE from Fossil-wiki into HTML and write
** the resulting HTML on standard output.
**
** Options:
** --buttons Set the WIKI_BUTTONS flag
** --dark-pikchr Render pikchrs in dark mode
** --flow Render as text using comment_format
** --htmlonly Set the WIKI_HTMLONLY flag
** --inline Set the WIKI_INLINE flag
** --linksonly Set the WIKI_LINKSONLY flag
** -m TEXT Use TEXT in place of the content of FILE
** --mark Add <mark>...</mark> around problems
** --nobadlinks Set the WIKI_NOBADLINKS flag
** --text Run the output through html_to_plaintext()
** --type Break down the return code from wiki_convert()
*/
void test_wiki_render(void){
Blob in, out;
int flags = 0;
int bText;
int bFlow = 0;
int showType = 0;
int mType;
const char *zIn;
if( find_option("buttons",0,0)!=0 ) flags |= WIKI_BUTTONS;
if( find_option("htmlonly",0,0)!=0 ) flags |= WIKI_HTMLONLY;
if( find_option("linksonly",0,0)!=0 ) flags |= WIKI_LINKSONLY;
if( find_option("nobadlinks",0,0)!=0 ) flags |= WIKI_NOBADLINKS;
if( find_option("inline",0,0)!=0 ) flags |= WIKI_INLINE;
if( find_option("mark",0,0)!=0 ) flags |= WIKI_MARK;
if( find_option("dark-pikchr",0,0)!=0 ){
pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE );
}
bText = find_option("text",0,0)!=0;
bFlow = find_option("flow",0,0)!=0;
showType = find_option("type",0,0)!=0;
zIn = find_option("msg","m",1);
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
verify_all_options();
if( (zIn==0 && g.argc!=3) || (zIn!=0 && g.argc!=2) ) usage("FILE");
blob_zero(&out);
if( zIn ){
blob_init(&in, zIn, -1);
}else{
blob_read_from_file(&in, g.argv[2], ExtFILE);
}
mType = wiki_convert(&in, &out, flags);
if( bText ){
Blob txt;
int htot = HTOT_TRIM;
if( terminal_is_vt100() ) htot |= HTOT_VT100;
if( bFlow ) htot |= HTOT_FLOW;
blob_init(&txt, 0, 0);
html_to_plaintext(blob_str(&out),&txt, htot);
blob_reset(&out);
out = txt;
}
if( bFlow ){
fossil_print(" ");
comment_print(blob_str(&out), 0, 3, terminal_get_width(80)-3,
get_comment_format());
}else{
blob_write_to_file(&out, "-");
}
if( showType ){
fossil_print("%.*c\nResult Codes:", terminal_get_width(80)-1, '*');
if( mType & RENDER_LINK ) fossil_print(" LINK");
if( mType & RENDER_ENTITY ) fossil_print(" ENTITY");
if( mType & RENDER_TAG ) fossil_print(" TAG");
if( mType & RENDER_BLOCKTAG ) fossil_print(" BLOCKTAG");
if( mType & RENDER_BLOCK ) fossil_print(" BLOCK");
if( mType & RENDER_MARK ) fossil_print(" MARK");
if( mType & RENDER_BADLINK ) fossil_print(" BADLINK");
if( mType & RENDER_BADTARGET ) fossil_print(" BADTARGET");
if( mType & RENDER_BADTAG ) fossil_print(" BADTAG");
if( mType & RENDER_BADENTITY ) fossil_print(" BADENTITY");
if( mType & RENDER_BADHTML ) fossil_print(" BADHTML");
if( mType & RENDER_ERROR ) fossil_print(" ERROR");
fossil_print("\n");
}
}
/*
** COMMAND: test-markdown-render
**
** Usage: %fossil test-markdown-render FILE ...
**
** Render markdown in FILE as HTML on stdout.
** Options:
**
** --dark-pikchr Render pikchrs in dark mode
** --lint-footnotes Print stats for footnotes-related issues
** --safe Restrict the output to use only "safe" HTML
** --text Run the output through html_to_plaintext().
*/
void test_markdown_render(void){
Blob in, out;
int i;
int bSafe = 0, bFnLint = 0, bText = 0;
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
bSafe = find_option("safe",0,0)!=0;
bFnLint = find_option("lint-footnotes",0,0)!=0;
if( find_option("dark-pikchr",0,0)!=0 ){
pikchr_to_html_add_flags( PIKCHR_PROCESS_DARK_MODE );
}
bText = find_option("text",0,0)!=0;
verify_all_options();
for(i=2; i<g.argc; i++){
blob_zero(&out);
blob_read_from_file(&in, g.argv[i], ExtFILE);
if( g.argc>3 ){
fossil_print("<!------ %h ------->\n", g.argv[i]);
}
markdown_to_html(&in, 0, &out);
safe_html_context( bSafe ? DOCSRC_UNTRUSTED : DOCSRC_TRUSTED );
safe_html(&out);
if( bText ){
Blob txt;
blob_init(&txt, 0, 0);
html_to_plaintext(blob_str(&out), &txt, HTOT_VT100);
blob_reset(&out);
out = txt;
}
blob_write_to_file(&out, "-");
blob_reset(&in);
blob_reset(&out);
}
if( bFnLint && (g.ftntsIssues[0] || g.ftntsIssues[1]
|| g.ftntsIssues[2] || g.ftntsIssues[3] )){
fossil_fatal("There were issues with footnotes:\n"
|
| ︙ | ︙ | |||
1988 1989 1990 1991 1992 1993 1994 1995 | ** ** [target] ** [target|...] ** ** Where "target" can be either an artifact ID prefix or a wiki page ** name. For each such hyperlink found, add an entry to the ** backlink table. */ | > > | < < < < < | 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 |
**
** [target]
** [target|...]
**
** Where "target" can be either an artifact ID prefix or a wiki page
** name. For each such hyperlink found, add an entry to the
** backlink table.
**
** The return value is a mask of RENDER_ flags.
*/
int wiki_extract_links(
char *z, /* The wiki text from which to extract links */
Backlink *pBklnk, /* Backlink extraction context */
int flags /* wiki parsing flags */
){
Renderer renderer;
int tokenType;
ParsedMarkup markup;
int n;
int wikiHtmlOnly = 0;
memset(&renderer, 0, sizeof(renderer));
renderer.state = ALLOW_WIKI|AT_NEWLINE|AT_PARAGRAPH;
if( wikiUsesHtml() ){
renderer.state |= WIKI_HTMLONLY;
wikiHtmlOnly = 1;
}
while( z[0] ){
if( wikiHtmlOnly ){
n = nextRawToken(z, &renderer, &tokenType);
}else{
n = nextWikiToken(z, &renderer, &tokenType);
}
|
| ︙ | ︙ | |||
2091 2092 2093 2094 2095 2096 2097 |
if( markup.endTag ){
renderer.state |= ALLOW_WIKI;
}else{
renderer.state &= ~ALLOW_WIKI;
}
}else
| < < < < < < | 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 |
if( markup.endTag ){
renderer.state |= ALLOW_WIKI;
}else{
renderer.state &= ~ALLOW_WIKI;
}
}else
/* Generate end-tags */
if( markup.endTag ){
popStackToTag(&renderer, markup.iCode);
}else
/* Push <div> markup onto the stack together with the id=ID attribute.
*/
|
| ︙ | ︙ | |||
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 |
default: {
break;
}
}
z += n;
}
free(renderer.aStack);
}
/*
** Return the length, in bytes, of the HTML token that z is pointing to.
*/
int html_token_length(const char *z){
int n;
| > | 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 |
default: {
break;
}
}
z += n;
}
free(renderer.aStack);
return renderer.mRender;
}
/*
** Return the length, in bytes, of the HTML token that z is pointing to.
*/
int html_token_length(const char *z){
int n;
|
| ︙ | ︙ | |||
2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 |
blob_zero(&out);
htmlTidy(blob_str(&in), &out);
blob_reset(&in);
fossil_puts(blob_buffer(&out), 0, blob_size(&out));
blob_reset(&out);
}
}
/*
** Remove all HTML markup from the input text. The output written into
** pOut is pure text.
**
** Put the title on the first line, if there is any <title> markup.
** If there is no <title>, then create a blank first line.
*/
| > > > > > > > > > > > > > > > > > > > > > > | | | | | | > > > > > > > > > > > > > > > > > | > > > | > | < | < | < < | < < | > | | | > | | < | > | | | > | | | > > | > > > | < < > > | < < | > | > | > > > > > > > | | 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 |
blob_zero(&out);
htmlTidy(blob_str(&in), &out);
blob_reset(&in);
fossil_puts(blob_buffer(&out), 0, blob_size(&out));
blob_reset(&out);
}
}
#if INTERFACE
/*
** Allowed flag options for html_to_plaintext().
*/
#define HTOT_VT100 0x01 /* <mark> becomes ^[[91m */
#define HTOT_FLOW 0x02 /* Collapse internal whitespace to a single space */
#define HTOT_TRIM 0x04 /* Trim off leading and trailing whitespace */
#endif /* INTERFACE */
/*
** Add <MARK> or </MARK> to the output, or similar VT-100 escape
** codes.
*/
static void addMark(Blob *pOut, int mFlags, int isClose){
static const char *az[4] = { "<MARK>", "</MARK>", "\033[91m", "\033[0m" };
int i = 0;
if( isClose ) i++;
if( mFlags & HTOT_VT100 ) i += 2;
blob_append(pOut, az[i], -1);
}
/*
** Remove all HTML markup from the input text. The output written into
** pOut is pure text.
**
** Put the title on the first line, if there is any <title> markup.
** If there is no <title>, then create a blank first line.
*/
void html_to_plaintext(const char *zIn, Blob *pOut, int mFlags){
int n;
int i, j;
int bFlow = 0; /* Transform internal WS into a single space */
int prevWS = 1; /* Previous output was whitespace or start of msg */
int nMark = 0; /* True if inside of <mark>..</mark> */
for(i=0; fossil_isspace(zIn[i]); i++){}
if( i>0 && (mFlags & HTOT_TRIM)==0 ){
blob_append(pOut, zIn, i);
}
zIn += i;
if( mFlags & HTOT_FLOW ) bFlow = 1;
while( zIn[0] ){
n = html_token_length(zIn);
if( zIn[0]=='<' && n>1 ){
int isCloseTag;
int eTag;
int eType;
char zTag[32];
prevWS = 0;
isCloseTag = zIn[1]=='/';
for(i=0, j=1+isCloseTag; i<30 && fossil_isalnum(zIn[j]); i++, j++){
zTag[i] = fossil_tolower(zIn[j]);
}
zTag[i] = 0;
eTag = findTag(zTag);
eType = aMarkup[eTag].iType;
if( eTag==MARKUP_INVALID && fossil_strnicmp(zIn,"<style",6)==0 ){
zIn += n;
while( zIn[0] ){
n = html_token_length(zIn);
if( fossil_strnicmp(zIn, "</style",7)==0 ) break;
zIn += n;
}
if( zIn[0]=='<' ) zIn += n;
continue;
}
if( eTag==MARKUP_INVALID && strcmp(zTag,"mark")==0 ){
if( isCloseTag && nMark ){
addMark(pOut, mFlags, 1);
nMark = 0;
}else if( !isCloseTag && !nMark ){
addMark(pOut, mFlags, 0);
nMark = 1;
}
zIn += n;
continue;
}
if( eTag==MARKUP_TITLE ){
if( isCloseTag && (mFlags & HTOT_FLOW)==0 ){
bFlow = 0;
}else{
bFlow = 1;
}
}
if( !isCloseTag && (eType & (MUTYPE_BLOCK|MUTYPE_TABLE))!=0 ){
blob_append_char(pOut, '\n');
}
}else if( fossil_isspace(zIn[0]) ){
if( bFlow==0 ){
if( zIn[n]==0 && (mFlags & HTOT_TRIM) ) break;
blob_append(pOut, zIn, n);
}else if( !prevWS ){
prevWS = 1;
blob_append_char(pOut, ' ');
zIn += n;
n = 0;
}
}else if( zIn[0]=='&' ){
u32 c = '?';
prevWS = 0;
if( zIn[1]=='#' ){
c = atoi(&zIn[2]);
if( c==0 ) c = '?';
}else{
static const struct { int n; u32 c; char *z; } aEntity[] = {
{ 5, '&', "&" },
{ 4, '<', "<" },
{ 4, '>', ">" },
{ 6, ' ', " " },
{ 6, '"', """ },
};
int jj;
for(jj=0; jj<count(aEntity); jj++){
if( aEntity[jj].n==n && strncmp(aEntity[jj].z,zIn,n)==0 ){
c = aEntity[jj].c;
break;
}
}
}
if( c<0x00080 ){
blob_append_char(pOut, c & 0xff);
}else if( c<0x00800 ){
blob_append_char(pOut, 0xc0 + (u8)((c>>6)&0x1f));
blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
}else if( c<0x10000 ){
blob_append_char(pOut, 0xe0 + (u8)((c>>12)&0x0f));
blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
}else{
blob_append_char(pOut, 0xf0 + (u8)((c>>18)&0x07));
blob_append_char(pOut, 0x80 + (u8)((c>>12)&0x3f));
blob_append_char(pOut, 0x80 + (u8)((c>>6)&0x3f));
blob_append_char(pOut, 0x80 + (u8)(c&0x3f));
}
}else{
prevWS = 0;
blob_append(pOut, zIn, n);
}
zIn += n;
}
if( nMark ){
addMark(pOut, mFlags, 1);
}
}
/*
** COMMAND: test-html-to-text
**
** Usage: %fossil test-html-to-text [OPTIONS] FILE ...
**
** Read all files named on the command-line. Convert the file
** content from HTML to text and write the results on standard
** output.
**
** This command is intended as a test and debug interface for
** the html_to_plaintext() routine.
**
** Options:
**
** --vt100 Translate <mark> and </mark> into ANSI/VT100
** escapes to highlight the contained text.
*/
void test_html_to_text(void){
Blob in, out;
int i;
int mFlags = 0;
if( find_option("vt100",0,0)!=0 ) mFlags |= HTOT_VT100;
for(i=2; i<g.argc; i++){
blob_read_from_file(&in, g.argv[i], ExtFILE);
blob_zero(&out);
html_to_plaintext(blob_str(&in), &out, mFlags);
blob_reset(&in);
fossil_puts(blob_buffer(&out), 0, blob_size(&out));
blob_reset(&out);
}
}
/****************************************************************************
|
| ︙ | ︙ |
Changes to src/winhttp.c.
| ︙ | ︙ | |||
994 995 996 997 998 999 1000 | ** ** Creates a service. Available options include: ** ** -D|--display DISPLAY-NAME ** ** Sets the display name of the service. This name is shown ** by graphical interface programs. By default, the display name | | | 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 | ** ** Creates a service. Available options include: ** ** -D|--display DISPLAY-NAME ** ** Sets the display name of the service. This name is shown ** by graphical interface programs. By default, the display name ** is equal to the service name. ** ** -S|--start TYPE ** ** Sets the start type of the service. TYPE can be "manual", ** which means you need to start the service yourself with the ** 'fossil winsrv start' command or with the "net start" command ** from the operating system. If TYPE is set to "auto", the service |
| ︙ | ︙ | |||
1017 1018 1019 1020 1021 1022 1023 | ** used. ** ** -W|--password PASSWORD ** ** Password for the user account. ** ** The following options are more or less the same as for the "server" | | | 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 | ** used. ** ** -W|--password PASSWORD ** ** Password for the user account. ** ** The following options are more or less the same as for the "server" ** command and influence the behavior of the http server: ** ** --baseurl URL ** ** Use URL as the base (useful for reverse proxies) ** ** -P|--port TCPPORT ** |
| ︙ | ︙ |
Changes to src/zip.c.
| ︙ | ︙ | |||
650 651 652 653 654 655 656 |
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
int flg, eflg = 0;
char *zName = 0;
zip_set_timedate(pManifest->rDate);
| | | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
nPrefix = blob_size(&filename);
pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
if( pManifest ){
int flg, eflg = 0;
char *zName = 0;
zip_set_timedate(pManifest->rDate);
flg = db_get_manifest_setting(blob_str(&hash));
if( flg ){
/* eflg is the effective flags, taking include/exclude into account */
if( (pInclude==0 || glob_match(pInclude, "manifest"))
&& !glob_match(pExclude, "manifest")
&& (flg & MFESTFLG_RAW) ){
eflg |= MFESTFLG_RAW;
}
|
| ︙ | ︙ |
Deleted test/comment.test.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to tools/makemake.tcl.
| ︙ | ︙ | |||
565 566 567 568 569 570 571 |
writeln [string map [list <<<NEXT_LINE>>> \\] {
$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c
$(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@
| | | | > | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 |
writeln [string map [list <<<NEXT_LINE>>> \\] {
$(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c
$(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@
$(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c
$(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@
$(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c $(MAKEFILE_LIST)
$(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry <<<NEXT_LINE>>>
-sEXPORTED_RUNTIME_METHODS=cwrap,ccall,setValue,getValue,stackSave,stackAlloc,stackRestore <<<NEXT_LINE>>>
-sEXPORTED_FUNCTIONS=_pikchr,_pikchr_version $(SRCDIR_extsrc)/pikchr.c <<<NEXT_LINE>>>
-sENVIRONMENT=web <<<NEXT_LINE>>>
-sMODULARIZE <<<NEXT_LINE>>>
-sEXPORT_NAME=initPikchrModule <<<NEXT_LINE>>>
--minify 0
$(TCLSH) $(TOPDIR)/tools/randomize-js-names.tcl $(SRCDIR_extsrc)
@chmod -x $(SRCDIR_extsrc)/pikchr.wasm
wasm: $(SRCDIR_extsrc)/pikchr.js
#
# compile_commands.json support...
#
# We have to avoid applying compile_commands support to the in-tree
|
| ︙ | ︙ |
Changes to tools/mkindex.c.
| ︙ | ︙ | |||
83 84 85 86 87 88 89 | #include <assert.h> #include <string.h> /*************************************************************************** ** These macros must match similar macros in dispatch.c. ** ** Allowed values for CmdOrPage.eCmdFlags. */ | | | | | | | | | | | | | | | | > | 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
#include <assert.h>
#include <string.h>
/***************************************************************************
** These macros must match similar macros in dispatch.c.
**
** Allowed values for CmdOrPage.eCmdFlags. */
#define CMDFLAG_1ST_TIER 0x00001 /* Most important commands */
#define CMDFLAG_2ND_TIER 0x00002 /* Obscure and seldom used commands */
#define CMDFLAG_TEST 0x00004 /* Commands for testing only */
#define CMDFLAG_WEBPAGE 0x00008 /* Web pages */
#define CMDFLAG_COMMAND 0x00010 /* A command */
#define CMDFLAG_SETTING 0x00020 /* A setting */
#define CMDFLAG_VERSIONABLE 0x00040 /* A versionable setting */
#define CMDFLAG_BLOCKTEXT 0x00080 /* Multi-line text setting */
#define CMDFLAG_BOOLEAN 0x00100 /* A boolean setting */
#define CMDFLAG_RAWCONTENT 0x00200 /* Do not interpret webpage content */
#define CMDFLAG_SENSITIVE 0x00400 /* Security-sensitive setting */
#define CMDFLAG_HIDDEN 0x00800 /* Elide from most listings */
#define CMDFLAG_LDAVG_EXEMPT 0x01000 /* Exempt from load_control() */
#define CMDFLAG_ALIAS 0x02000 /* Command aliases */
#define CMDFLAG_KEEPEMPTY 0x04000 /* Do not unset empty settings */
#define CMDFLAG_ABBREVSUBCMD 0x08000 /* Abbreviated subcmd in help text */
/**************************************************************************/
/*
** Each entry looks like this:
*/
typedef struct Entry {
int eType; /* CMDFLAG_* values */
|
| ︙ | ︙ | |||
278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8);
}else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){
aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9);
}else if( j==6 && strncmp(&zLine[i], "hidden", 6)==0 ){
aEntry[nUsed].eType |= CMDFLAG_HIDDEN;
}else if( j==14 && strncmp(&zLine[i], "loadavg-exempt", 14)==0 ){
aEntry[nUsed].eType |= CMDFLAG_LDAVG_EXEMPT;
}else{
fprintf(stderr, "%s:%d: unknown option: '%.*s'\n",
zFile, nLine, j, &zLine[i]);
nErr++;
}
}
| > > > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
aEntry[nUsed].zDflt = string_dup(&zLine[i+8], j-8);
}else if( j>9 && strncmp(&zLine[i], "variable=", 9)==0 ){
aEntry[nUsed].zVar = string_dup(&zLine[i+9], j-9);
}else if( j==6 && strncmp(&zLine[i], "hidden", 6)==0 ){
aEntry[nUsed].eType |= CMDFLAG_HIDDEN;
}else if( j==14 && strncmp(&zLine[i], "loadavg-exempt", 14)==0 ){
aEntry[nUsed].eType |= CMDFLAG_LDAVG_EXEMPT;
}else if( (j==23 && strncmp(&zLine[i], "abbreviated-subcommands", 23)==0)
|| (j==12 && strncmp(&zLine[i], "abbrv-subcom", 12)==0) ){
aEntry[nUsed].eType |= CMDFLAG_ABBREVSUBCMD;
}else{
fprintf(stderr, "%s:%d: unknown option: '%.*s'\n",
zFile, nLine, j, &zLine[i]);
nErr++;
}
}
|
| ︙ | ︙ |
Added tools/randomize-js-names.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#!/usr/bin/tclsh
#
# This script is run as part of "make wasm". After emcc has
# run to generate extsrc/pikchr.wasm and extsrc/pikchr.js from
# extsrc/pikchr.c, we need to make changes to these filenames to
# work around caching problems.
#
# (1) in extsrc/pikchr.js -> change "pikchr.wasm" into
# "pikchr-vNNNNNNNN.wasm" where Ns are random digits.
#
# (2) in extsrc/pikchr-worker.js -> change "pikchr-vNNNNNNNN.js"
# by altering the random digits N.
#
set DIR extsrc
if {[llength $argv]>0} {
set DIR [lindex $argv 0]
}
set R [expr {int(rand()*10000000000)+1000000000}]
set in [open $DIR/pikchr.js rb]
set f1 [read $in]
close $in
set f1mod [regsub {\ypikchr(-v\d+)?\.wasm\y} $f1 "pikchr-v$R.wasm"]
set out [open $DIR/pikchr.js wb]
puts -nonewline $out $f1mod
close $out
puts "modified $DIR/pikchr.js to reference \"pikchr-v$R.wasm\""
set in [open $DIR/pikchr-worker.js rb]
set f1 [read $in]
close $in
set f1mod [regsub {\ypikchr(-v\d+)?\.js\y} $f1 "pikchr-v$R.js"]
set out [open $DIR/pikchr-worker.js wb]
puts -nonewline $out $f1mod
close $out
puts "modified $DIR/pikchr-worker.js to reference \"pikchr-v$R.js\""
|
Added win/build32.bat.
> > > | 1 2 3 | REM Based on /wiki/Release%20Build%20How-To nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 FOSSIL_ENABLE_WINXP=1 OPTIMIZATIONS=4 clean fossil.exe dumpbin /dependents fossil.exe |
Added win/build64.bat.
> > > | 1 2 3 | REM Based on /wiki/Release%20Build%20How-To nmake /f Makefile.msc FOSSIL_ENABLE_SSL=1 OPTIMIZATIONS=4 clean fossil.exe dumpbin /dependents fossil.exe |
Changes to www/alerts.md.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # Email Alerts ## Overview Beginning with version 2.7, Fossil can send email messages to subscribers to alert them to changes in the repository: * New [checkins](/help?cmd=ci) * [Ticket](./tickets.wiki) changes * [Wiki](./wikitheory.wiki) page changes * New and edited [forum](./forum.wiki) posts * Announcements Subscribers can elect to receive emails as soon as these events happen, or they can receive a daily digest of the events instead. Email alerts are sent by a [Fossil server](./server/), which must be [set up](#quick) by the Fossil administrator to send email. | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # Email Alerts ## Overview Beginning with version 2.7, Fossil can send email messages to subscribers to alert them to changes in the repository: * New [checkins](/help?cmd=ci) * [Ticket](./tickets.wiki) changes * [Wiki](./wikitheory.wiki) page changes * New and edited [forum](./forum.wiki) posts * Users receiving [new permissions](./caps/index.md) (admins only) * Announcements Subscribers can elect to receive emails as soon as these events happen, or they can receive a daily digest of the events instead. Email alerts are sent by a [Fossil server](./server/), which must be [set up](#quick) by the Fossil administrator to send email. |
| ︙ | ︙ | |||
513 514 515 516 517 518 519 520 521 522 523 524 525 526 | * The Verified checkbox is initially unchecked for subscriber-only email addresses until the user clicks the link in the verification email. This checkbox lets the Fossil Admin user manually verify the user, such as in the case where the verification email message got lost. Unchecking this box does not cause another verification email to be sent. This screen also allows a Fossil Admin user to perform other activities on behalf of a subscriber which they could do themselves, such as to [unsubscribe](#unsub) them. <a id="backup"></a> | > > > > | 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | * The Verified checkbox is initially unchecked for subscriber-only email addresses until the user clicks the link in the verification email. This checkbox lets the Fossil Admin user manually verify the user, such as in the case where the verification email message got lost. Unchecking this box does not cause another verification email to be sent. * Admin users (only) may activate the "user elevation" subscription, which sends a notification when a user is created or is explicitly assigned permission they did not formerly have. This screen also allows a Fossil Admin user to perform other activities on behalf of a subscriber which they could do themselves, such as to [unsubscribe](#unsub) them. <a id="backup"></a> |
| ︙ | ︙ |
Changes to www/build.wiki.
| ︙ | ︙ | |||
338 339 340 341 342 343 344 | Fossil has builtin support for processing specific features using <tt>libfuzzer</tt>. The features which can be tested this way are found in the help text for the [/help?cmd=test-fuzz|test-fuzz command]. Fuzzing requires: | < < | < < < < < < | < < > < < < | | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
Fossil has builtin support for processing specific features using
<tt>libfuzzer</tt>. The features which can be tested this way are
found in the help text for the [/help?cmd=test-fuzz|test-fuzz
command].
Fuzzing requires:
* The clang C compiler.
* libfuzzer. On Ubuntu-derived systems, it can be installed with
<tt>apt install libfuzzer-XYZ</tt>, where XYZ is a version number
(several versions may be available on any given system)
Compile as follows:
<pre><code>make clean
make TCCFLAGS='-DFOSSIL_FUZZ -fsanitize=fuzzer,address,undefined -O0 -g' CC=clang
</code></pre>
The resulting <tt>fossil</tt> binary differs from the standard
one primarily in that it runs the <tt>test-fuzz</tt> command by
default. It needs to be told what to fuzz and needs to be given a
directory of input files to seed the fuzzer with:
<pre><code>$ mkdir cases
# Copy input files into ./cases. e.g. when fuzzing the markdown
# processor, copy any to-be-tested .md files into that directory.
# Then start the fuzzer:
$ ./fossil-fuzz --fuzztype markdown cases
</code></pre>
As it works, it writes its mutated test files into the "cases"
directory, each one named in the form of a hash. When it finds a
problem it will produce a stack trace for the offending code, will
output the name of the file which triggered the crash (named
<tt>cases/SOME_HASH</tt>) and may, depending on the nature of the
problem, produce a file named <tt>crash-SOMETHING</tt>. In theory the
crash file can be fed directly back into the fuzzer to reproduce the
problem:
|
| ︙ | ︙ | |||
501 502 503 504 505 506 507 |
to give JS code access to the API exported by the WASM file.
When a new version of <tt>extsrc/pikchr.c</tt> is installed, the
files <tt>pikchr.{js,wasm}</tt> will need to be recompiled to account
for that. Running <tt>make wasm</tt> will, if the build is set up for
the emsdk, recompile those:
| > > | | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 |
to give JS code access to the API exported by the WASM file.
When a new version of <tt>extsrc/pikchr.c</tt> is installed, the
files <tt>pikchr.{js,wasm}</tt> will need to be recompiled to account
for that. Running <tt>make wasm</tt> will, if the build is set up for
the emsdk, recompile those:
<pre><code>$ rm extsrc/pikchr.{js,wasm}
# ^^^^ that rm has proven necessary in order to ensure rebuilds
$ make wasm
./tools/emcc.sh -o extsrc/pikchr.js ...
$ ls -la extsrc/pikchr.{js,wasm}
-rw-rw-r-- 1 stephan stephan 17263 Jun 8 03:59 extsrc/pikchr.js
-rw-rw-r-- 1 stephan stephan 97578 Jun 8 03:59 extsrc/pikchr.wasm
</code></pre>
<div class="sidebar">If that fails with a message along the lines of
|
| ︙ | ︙ |
Changes to www/cgi.wiki.
| ︙ | ︙ | |||
71 72 73 74 75 76 77 78 | If it is present, and if the [#directory:|<b>directory:</b>] option is used, and if the PATH_INFO string is empty, then Fossil will show a list of available Fossil repositories. The "skin" of the reply is determined by the first repository in the list that has a non-zero [/help?cmd=repolist-skin|repolist-skin] setting. If no repository has such a non-zero repolist-skin setting, then | > | > > > | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | If it is present, and if the [#directory:|<b>directory:</b>] option is used, and if the PATH_INFO string is empty, then Fossil will show a list of available Fossil repositories. The "skin" of the reply is determined by the first repository in the list that has a non-zero [/help?cmd=repolist-skin|repolist-skin] setting. If no repository has such a non-zero repolist-skin setting, then the repository list is generic HTML without any decoration, with the page title taken from the <tt>FOSSIL_REPOLIST_TITLE</tt> environment variable. The variable can be defined in the CGI control file using the [#setenv|<tt>setenv:</tt>] statement. The repolist-generated page recurses into subdirectories and will list all <tt>*.fossil</tt> files found, with the following exceptions: * Filenames starting with a period are treated as "hidden" and skipped. * Subdirectory names which match the base name of a fossil file in |
| ︙ | ︙ |
Changes to www/changes.wiki.
1 2 3 4 | <title>Change Log</title> <h2 id='v2_26'>Changes for version 2.26 (pending)</h2> | | > | | > > > > > > > > | > | | | > > > > > > > > | | | > > > > > > > > > > > > | | | < < < < > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<title>Change Log</title>
<h2 id='v2_26'>Changes for version 2.26 (pending)</h2>
* Enhancements to [/help?cmd=diff|fossil diff] and similar:
<ol type="a">
<li> The --from can optionally accepts a directory name as its argument,
and uses files under that directory as the baseline for the diff.
<li> For "gdiff", if no [/help?cmd=gdiff-command|gdiff-command setting]
is defined, Fossil tries to do a --tk diff if "tclsh" and "wish"
are available, or a --by diff if not.
<li> The "Reload" button is added to --tk diffs, to bring the displayed
diff up to date with the latest changes on disk.
<li> Add the "Hide diffs/Show diffs" toggle to web-UI diff pages that show
diffs of multiple files.
</ol>
* Added the [/help?cmd=/ckout|/ckout web page] to provide information
about pending changes in a working check-out
* Enhancements to the [/help?cmd=ui|fossil ui] command:
<ol type="a">
<li> Defaults to using the new [/help?cmd=/ckout|/ckout page] as its
start page. Or, if the new "--from PATH" option is present, the
default start page becomes "/ckout?exbase=PATH".
<li> The new "--extpage FILENAME" option opens the named file as if it
where in a [./serverext.wiki|CGI extension]. Example usage: the
person editing this change log has
"fossil ui --extpage www/changes.wiki" running and hence can
press "Reload" on the web browser to view edits.
</ol>
* Enhancements to [/help?cmd=merge|fossil merge]:
<ol type="a">
<li> Added the [/help?cmd=merge-info|fossil merge-info] command and
especially the --tk option to that command, to provide analysis
of the most recent merge or update operation.
<li> When a merge conflict occurs, a new section is added to the conflict
text that shows Fossil's suggested resolution to the conflict.
</ol>
* Enhancements to [/help?cmd=commit|fossil commit]:
<ol type="a">
<li> If Fossil sees potential formatting mistakes (ex: bad hyperlinks)
in the check-in comment, it will alert the developer and give
him or her the opportunity to edit the comment before continuing.
This feature is controllable by the
[/help?cmd=verify-comments|verify-comments setting].
<li> The new "--if-changes" option causes the commit to become
a quiet no-op if there are no pending changes.
<li> Added the ability to sign check-ins with SSH keys.
<li> Issue a warning if a user tries to commit on a check-in where the
branch has been changed.
<li> The interactive checkin comment prompt shows the formatting rules
set for that repository.
</ol>
* Deprecate the --comfmtflags and --comment-format global options and
no longer list them in the built-in help, but keep them working for
backwards compatibility.
Alternative TTY comment formatting can still be specified using the
[/help?cmd=comment-format|comment-format setting], if desired. The
default comment format is now called "canonical", not "legacy".
* Enhancements to the [/help?cmd=/timeline|/timeline page]:
<ol type="a">
<li> Added the "ml=" ("Merge-in List") query parameter that works
like "rl=" ("Related List") but adds "mionly" style related
check-ins instead of the full "rel" style.
<li> For "tl=", "rl=", and "ml=", the order of the branches in the
graph now tries to match the order of the branches named in
|
| ︙ | ︙ | |||
41 42 43 44 45 46 47 48 |
GLOB characters, then the matching style ("ms=") is set to GLOB
automatically and the "ms=" query parameter can be omitted.
<li> Enhance the "ymd" query parameter so that when used like
"ymd=YYYYMMDD-YYYYMMDD" it shows all events in the range of
dates specified.
<li> Accept the "Z" (Zulu-time) suffix on date arguments for the
"ymd" and "yw" query parameters.
</ol>
| > > > > > > > > > > > > | < > | > > | > > | | | > > > > > > > > > > > > > > > > > > > > > > > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
GLOB characters, then the matching style ("ms=") is set to GLOB
automatically and the "ms=" query parameter can be omitted.
<li> Enhance the "ymd" query parameter so that when used like
"ymd=YYYYMMDD-YYYYMMDD" it shows all events in the range of
dates specified.
<li> Accept the "Z" (Zulu-time) suffix on date arguments for the
"ymd" and "yw" query parameters.
<li> The new "min" query parameter, when added to a from=,to= query,
collapses long runs of check-ins on the same branch into just
end-points.
<li> The p= and d= parameters an reference different check-ins, which
case the timeline shows those check-ins that are both ancestors
of p= and descendants of d=.
<li> The saturation and intensity of user-specified checkin and branch
colors are automatically adjusted to keep the colors
compatible with the current skin, unless the
[/help?cmd=raw-bgcolor|raw-bgcolor setting] is turned on. The
/test-bgcolor page was added to
test and visualize how these adjustments.
</ol>
* The [/help?cmd=/docfile|/docfile webpage] was added. It works like
/doc but keeps the title of markdown documents with the document rather
that moving it up to the page title.
* Added the [/help?cmd=/clusterlist|/clusterlist page] for analysis
and debugging
* Added the "artifact_to_json(NAME)" SQL function that returns a JSON
decoding of the artifact described by NAME.
* Improvements to the [/help?cmd=patch|fossil patch] command:
<ol type="a">
<li> Fix a bug in "fossil patch create" that causes
[/help?cmd=revert|fossil revert] operations that happened
on individualfiles after a [/help?cmd=merge|fossil merge]
to be omitted from the patch.
<li> Added the [/help?cmd=patch|patch alias] command for managing
aliases for remote checkout names.
</ol>
* Enhancements to on-line help and the [/help?cmd=help|fossil help] command:
<ol type="a">
<li> Add the ability to search the help text, either in the UI
(on the [/help?cmd=/search|/search page]) or from the command-line
(using the "[/help?cmd=search|fossil search -h PATTERN]" command.)
<li> Accepts an optional SUBCOMMAND argument following the
COMMAND argument and only shows results for the specified
subcommand, not the entire command.
<li> The -u (--usage) option shows only the command-line syntax
<li> The -o (--options) option shows only the command-line options
</ol>
* Added the ability to attach wiki pages to a ticket for extended
descriptions.
* Added the "hash" query parameter to the
[/help?cmd=/whatis|/whatis webpage].
* Add a "user elevation" [/doc/trunk/www/alerts.md|subscription]
which alerts subscribers when an admin creates a new user or
adds new permissions to one.
* Diverse minor fixes and additions.
<h2 id='v2_25'>Changes for version 2.25 (2024-11-06)</h2>
* The "[/help?cmd=ui|fossil ui /]" command now works even for repositories
that have non-ASCII filenames
* Add the [/help?cmd=tree|fossil tree] command.
* On case-insensitive filesystems, store files using the filesystem's
|
| ︙ | ︙ |
Changes to www/env-opts.md.
| ︙ | ︙ | |||
37 38 39 40 41 42 43 | `--comfmtflags NUMBER`: Specify flags that control how check-in comments and certain other text outputs are formatted for display. The flags are individual bits in `NUMBER`, which must be specified in base 10: * _0_ — Uses the revised algorithm with no special handling. | | > > > > > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
`--comfmtflags NUMBER`: Specify flags that control how check-in comments
and certain other text outputs are formatted for display. The flags are
individual bits in `NUMBER`, which must be specified in base 10:
* _0_ — Uses the revised algorithm with no special handling.
* _1_ — Uses the canonical algorithm, other flags are ignored.
* _2_ — Trims leading and trailing carriage-returns and line-feeds
where they do not materially impact pre-existing formatting
(i.e. at the start of the comment string _and_ right before
line indentation).
* _4_ — Trims leading and trailing spaces where they do not materially
impact the pre-existing formatting (i.e. at the start of the
comment string _and_ right before line indentation).
* _8_ — Attempts to break lines on word boundaries while honoring the
logical line length.
* _16_ — Looks for the original comment text within the text being
printed. Upon matching, a new line will be emitted, thus
preserving more of the pre-existing formatting.
`--comment-format NUMBER`: Alias for `--comfmtflags NUMBER`.
> NOTE: As of Fossil version 2.26, use of the `--comfmtflags` and
> `--comment-format` options is no longer recommended and they are
> no longer documented, but retained for backwards compatibility.
`--errorlog ERRLOG`: Name a file to which fossil will log panics,
errors, and warnings.
`--help`: If `--help` is found anywhere on the command line, translate
the command to `fossil help cmdname` where `cmdname` is the first
|
| ︙ | ︙ | |||
141 142 143 144 145 146 147 148 149 150 151 152 153 154 | local (or remote) testing of the moderation subsystem and its impact on the contents and status of wiki pages. `FOSSIL_HOME`: Location of [configuration database][configdb]. See the [configuration database location][configloc] description for additional information. `FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for SEE as text to be hashed into the actual encryption key. This has no effect if Fossil was not compiled with SEE support enabled. `FOSSIL_USER`: Name of the default user account if the checkout, local | > > > > > | 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | local (or remote) testing of the moderation subsystem and its impact on the contents and status of wiki pages. `FOSSIL_HOME`: Location of [configuration database][configdb]. See the [configuration database location][configloc] description for additional information. `FOSSIL_REPOLIST_TITLE`: The page title of the "Repository List" page loaded by the `fossil all ui` or `fossil ui /` commands. Only used if none of the listed repositories has the `repolist_skin` property set. Can be set from the [CGI control file][cgictlfile]. `FOSSIL_USE_SEE_TEXTKEY`: If set, treat the encryption key string for SEE as text to be hashed into the actual encryption key. This has no effect if Fossil was not compiled with SEE support enabled. `FOSSIL_USER`: Name of the default user account if the checkout, local |
| ︙ | ︙ | |||
208 209 210 211 212 213 214 215 216 217 218 219 220 221 | `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. `LOGNAME`: Name of the logged in user on many Unix-like platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `PATH`: Used by most platforms to locate programs invoked without a fully qualified name. Explicitly used by `fossil ui` on certain platforms to choose the browser to launch. `PATH_INFO`: If defined, included in error log messages. | > > > > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | `FOSSIL_HOME`, `LOCALAPPDATA` (Windows), `APPDATA` (Windows), `HOMEDRIVE` and `HOMEPATH` (Windows, used together), and `HOME` is used as the location of the `~/.fossil` file. `LOGNAME`: Name of the logged in user on many Unix-like platforms. Used as the fossil user name if `FOSSIL_USER` is not specified. See the discussion of Fossil Username below for a lot more detail. `NO_COLOR`: If defined and not set to a `false` value (i.e. "off", "no", "false", "0"), the `fossil search` command skips colorization of console output using ANSI escape codes (VT100). `PATH`: Used by most platforms to locate programs invoked without a fully qualified name. Explicitly used by `fossil ui` on certain platforms to choose the browser to launch. `PATH_INFO`: If defined, included in error log messages. |
| ︙ | ︙ | |||
462 463 464 465 466 467 468 | will happen on all platforms. ### Web browser Occasionally, fossil wants to launch a web browser for the user, most obviously as part of the `fossil ui` command. In that specific case, | | | > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 | will happen on all platforms. ### Web browser Occasionally, fossil wants to launch a web browser for the user, most obviously as part of the `fossil ui` command. In that specific case, the browser is launched pointing at the web server started by `fossil ui` listening on a private TCP port. On all platforms, if the local or global settings `web-browser` is set, that is the command used to open a URL. Otherwise, the specific actions vary by platform. On Unix-like platforms other than Apple's, it looks for the first program from the list `xdg-open`, `gnome-open`, `firefox`, and `google-chrome` that it can find on the `PATH`. On Apple platforms, it assumes that `open` is the command to open a URL in the user's configured default browser. On Windows platforms, it assumes that `start` is the command to open a URL in the user's configured default browser. [configdb]: ./tech_overview.wiki#configdb [configloc]: ./tech_overview.wiki#configloc [cgictlfile]: ./cgi.wiki |
Changes to www/fileformat.wiki.
| ︙ | ︙ | |||
59 60 61 62 63 64 65 | repository. Fossil recognizes the following kinds of structural artifacts: <ul> <li> [#manifest | Manifests] </li> <li> [#cluster | Clusters] </li> | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | repository. Fossil recognizes the following kinds of structural artifacts: <ul> <li> [#manifest | Manifests] </li> <li> [#cluster | Clusters] </li> <li> [#ctrl | Control (a.k.a. Tag) Artifacts] </li> <li> [#wikichng | Wiki Pages] </li> <li> [#tktchng | Ticket Changes] </li> <li> [#attachment | Attachments] </li> <li> [#event | TechNotes] </li> <li> [#forum | Forum Posts] </li> </ul> |
| ︙ | ︙ | |||
171 172 173 174 175 176 177 | is optional. The file format might be extended with new permission letters in the future. The optional 4th argument is the name of the same file as it existed in the parent check-in. If the name of the file is unchanged from its parent, then the 4th argument is omitted. A manifest has zero or one <b>N</b> cards. The <b>N</b> card specifies the mimetype for the text in the comment of the <b>C</b> card. If the <b>N</b> card is omitted, a default mimetype | | > > > | 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | is optional. The file format might be extended with new permission letters in the future. The optional 4th argument is the name of the same file as it existed in the parent check-in. If the name of the file is unchanged from its parent, then the 4th argument is omitted. A manifest has zero or one <b>N</b> cards. The <b>N</b> card specifies the mimetype for the text in the comment of the <b>C</b> card. If the <b>N</b> card is omitted, a default mimetype is used. Note that the <b>N</b> card has never actually been used by any Fossil implementation. The implementation has always interpreted check-in comments according to the [/wiki_rules|Fossil Wiki formatting rules]. There are no current plans to ever change that. A manifest has zero or one <b>P</b> cards. Most manifests have one <b>P</b> card. The <b>P</b> card has a varying number of arguments that define other manifests from which the current manifest is derived. Each argument is a lowercase hexadecimal artifact hash of a predecessor manifest. All arguments to the <b>P</b> card must be unique within that card. |
| ︙ | ︙ | |||
271 272 273 274 275 276 277 | the <b>Z</b> card of a manifest. The argument to the <b>Z</b> card is the lower-case hexadecimal representation of the MD5 checksum of all prior cards in the cluster. The <b>Z</b> card is required. An example cluster from Fossil can be seen [/artifact/d03dbdd73a2a8 | here]. | | | | > > > > | 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | the <b>Z</b> card of a manifest. The argument to the <b>Z</b> card is the lower-case hexadecimal representation of the MD5 checksum of all prior cards in the cluster. The <b>Z</b> card is required. An example cluster from Fossil can be seen [/artifact/d03dbdd73a2a8 | here]. <h3 id="ctrl">2.3 Control (a.k.a. Tag) Artifacts</h3> Control artifacts are used to assign properties to other artifacts within the repository. Allowed cards in a control artifact are as follows: <div class="indent"> <b>D</b> <i>time-and-date-stamp</i><br /> <b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br /> <b>U</b> <i>user-name</i><br /> <b>Z</b> <i>checksum</i><br /> </div> Control articles are also referred to as Tag artifacts, but tags can also be applied via other artifact types, as described in [#summary|the Card Summary table]. A control artifact must have one <b>D</b> card, one <b>U</b> card, one <b>Z</b> card and one or more <b>T</b> cards. No other cards or other text is allowed in a control artifact. Control artifacts might be PGP clearsigned. The <b>D</b> card and the <b>Z</b> card of a control artifact are the same |
| ︙ | ︙ |
Changes to www/serverext.wiki.
| ︙ | ︙ | |||
30 31 32 33 34 35 36 | an "Extension Root Directory" or "extroot" as part of the [./server/index.html|server setup]. If the Fossil server is itself run as [./server/any/cgi.md|CGI], then add a line to the [./cgi.wiki#extroot|CGI script file] that says: <pre> | | | > | > > | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
an "Extension Root Directory" or "extroot" as part of the
[./server/index.html|server setup].
If the Fossil server is itself run as
[./server/any/cgi.md|CGI], then add a line to the
[./cgi.wiki#extroot|CGI script file] that says:
<pre>
extroot: <i>DIRECTORY</i>
</pre>
Or, if the Fossil server is being run using the
"[./server/any/none.md|fossil server]" or
"[./server/any/none.md|fossil ui]" or
"[./server/any/inetd.md|fossil http]" commands, then add an extra
"--extroot <i>DIRECTORY</i>" option to that command.
The <i>DIRECTORY</i> is the DOCUMENT_ROOT for the CGI.
Files in the DOCUMENT_ROOT are accessed via URLs like this:
<pre>
https://example-project.org/ext/<i>FILENAME</i>
</pre>
In other words, access files in DOCUMENT_ROOT by appending the filename
relative to DOCUMENT_ROOT to the [/help?cmd=/ext|/ext]
page of the Fossil server.
* Files that are readable but not executable are returned as static
content.
* Files that are executable are run as CGI.
<h3>2.1 Example #1</h3>
The source code repository for SQLite is a Fossil server that is run
as CGI. The URL for the source code repository is [https://sqlite.org/src].
The CGI script looks like this:
|
| ︙ | ︙ | |||
115 116 117 118 119 120 121 122 123 124 125 126 | script. (The extension mechanism is not required to use Wapp. You can use any kind of program you like. But the creator of SQLite and Fossil is fond of [https://www.tcl.tk|Tcl/Tk] and so he tends to gravitate toward Tcl-based technologies like Wapp.) The fileup1 script is a demo program that lets the user upload a file using a form, and then displays that file in the reply. There is a link on the page that causes the fileup1 script to return a copy of its own source-code, so you can see how it works. <h2 id="cgi-inputs">3.0 CGI Inputs</h2> The /ext extension mechanism is an ordinary CGI interface. Parameters are passed to the CGI program using environment variables. The following | > > > > > > > > > > > > > > > > > > > > > > > > > | | 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | script. (The extension mechanism is not required to use Wapp. You can use any kind of program you like. But the creator of SQLite and Fossil is fond of [https://www.tcl.tk|Tcl/Tk] and so he tends to gravitate toward Tcl-based technologies like Wapp.) The fileup1 script is a demo program that lets the user upload a file using a form, and then displays that file in the reply. There is a link on the page that causes the fileup1 script to return a copy of its own source-code, so you can see how it works. <h3>2.3 Example #3</h3> For Fossil versions dated 2025-03-23 and later, the "--extpage FILENAME" option to the [/help?cmd=ui|fossil ui] command is a short cut that treats FILENAME as a CGI extension. When the ui command starts up a new web browser pages, it points that page to the FILENAME extension. So if FILENAME is a static content file (such as an HTML file or [/md_rules|Markdown] or [/wiki_rules|Wiki] document), then the rendered content of the file is displayed. Meanwhile, the user can be editing the source text for that document in a separate window, and periodically pressing "Reload" on the web browser to instantly view the rendered results. For example, the author of this documentation page is running "<tt>fossil ui --extpage www/serverext.wiki</tt>" while editing this very paragraph, and presses Reload from time to time to view his edits. A same idea applies when developing new CGI applications using a script language (for example using [https://wapp.tcl.tk|Wapp]). Run the command "<tt>fossil ui --extpage SCRIPT</tt>" where SCRIPT is the name of the application script, while editing that script in a separate window, then press Reload periodically on the web browser to test the script. <h2 id="cgi-inputs">3.0 CGI Inputs</h2> The /ext extension mechanism is an ordinary CGI interface. Parameters are passed to the CGI program using environment variables. The following standard CGI environment variables are supplied: * AUTH_TYPE * AUTH_CONTENT * CONTENT_LENGTH * CONTENT_TYPE * DOCUMENT_ROOT * GATEWAY_INTERFACE |
| ︙ | ︙ |
Changes to www/settings.wiki.
1 2 | <title>Fossil Settings</title> | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <title>Fossil Settings</title> <h1>Using Fossil Settings</h1> Settings control the behaviour of fossil. They are set with the <tt>fossil settings</tt> command, or through the web interface in the Settings page in the Admin section. For a list of all settings, view the Settings page, or type <tt>fossil help settings</tt> from the command line. <h2 id="repo">1.0 Repository settings</h2> Settings are set on a per-repository basis. When you clone a repository, a subset of settings are copied to your local repository. If you make a change to a setting on your local repository, it is not synced back to the server when you <tt>push</tt> or <tt>sync</tt>. If you make a change on the server, you need to manually make the change on all repositories which are cloned from this repository. You can also set a setting globally on your local machine. The value will be used for all repositories cloned to your machine, unless overridden explicitly in a particular repository. Global settings can be set by using the <tt>-global</tt> option on the <tt>fossil settings</tt> command. <h2 id="versionable">2.0 "Versionable" settings</h2> Most of the settings control the behaviour of fossil on your local machine, largely acting to reflect your preference on how you want to use Fossil, how you communicate with the server, or options for hosting a repository on the web. However, for historical reasons, some settings affect how you work with |
| ︙ | ︙ |
Changes to www/th1.md.
| ︙ | ︙ | |||
225 226 227 228 229 230 231 232 233 234 235 236 237 238 | * [trace](#trace) * [unversioned content](#unversioned_content) * [unversioned list](#unversioned_list) * [utime](#utime) * [verifyCsrf](#verifyCsrf) * [verifyLogin](#verifyLogin) * [wiki](#wiki) Each of the commands above is documented by a block comment above their implementation in the th\_main.c or th\_tcl.c source files. All commands starting with "tcl", with the exception of "tclReady", require the Tcl integration subsystem be included at compile-time. Additionally, the "tcl" repository setting must be enabled at runtime | > | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | * [trace](#trace) * [unversioned content](#unversioned_content) * [unversioned list](#unversioned_list) * [utime](#utime) * [verifyCsrf](#verifyCsrf) * [verifyLogin](#verifyLogin) * [wiki](#wiki) * [wiki_assoc](#wiki_assoc) Each of the commands above is documented by a block comment above their implementation in the th\_main.c or th\_tcl.c source files. All commands starting with "tcl", with the exception of "tclReady", require the Tcl integration subsystem be included at compile-time. Additionally, the "tcl" repository setting must be enabled at runtime |
| ︙ | ︙ | |||
269 270 271 272 273 274 275 | <a id="bireqjs"></a>TH1 builtin_request_js Command -------------------------------------------------- * builtin_request_js NAME | | | | 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | <a id="bireqjs"></a>TH1 builtin_request_js Command -------------------------------------------------- * builtin_request_js NAME NAME must be the name of one of the [built-in javascript source files](/dir?ci=trunk&type=flat&name=src&re=js$). This command causes that javascript file to be appended to the delivered document. <a id="capexpr"></a>TH1 capexpr Command ----------------------------------------------------- * capexpr CAPABILITY-EXPR The capability expression is a list. Each term of the list is a cluster of [capability letters](./caps/ref.html). The overall expression is true if any one term is true. A single term is true if all letters within that term are true. Or, if the term begins with "!", then the term is true if none of the terms are true. Or, if the term begins with "@" then the term is true if all of the capability letters in that term are available to the "anonymous" user. Or, if the term is "*" then it is always true. |
| ︙ | ︙ | |||
859 860 861 862 863 864 865 866 867 868 869 870 871 872 | <a id="wiki"></a>TH1 wiki Command ----------------------------------- * wiki STRING Renders STRING as wiki content. Tcl Integration Commands ------------------------ When the Tcl integration subsystem is enabled, several commands are added to the Tcl interpreter. They are used to allow Tcl scripts access to the Fossil functionality provided via TH1. The following is a summary of the | > > > > > > > > > | 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 | <a id="wiki"></a>TH1 wiki Command ----------------------------------- * wiki STRING Renders STRING as wiki content. <a id="wiki_assoc"></a>TH1 wiki_assoc Command ----------------------------------- * wiki_assoc STRING STRING Renders the special wiki. The first string refers to the namespace (checkin, branch, tag, ticket). The second string specifies the concrete wiki page to be rendered. Tcl Integration Commands ------------------------ When the Tcl integration subsystem is enabled, several commands are added to the Tcl interpreter. They are used to allow Tcl scripts access to the Fossil functionality provided via TH1. The following is a summary of the |
| ︙ | ︙ |
Added www/title-test.md.
> > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 | # Markdown Doc Title > & " ' < Test Test of unusual characters in the title of Markdown formatted documents. The title should read: > Markdown Doc Title > & " ' < Test See also: * [](/doc/trunk/www/title-test.wiki) * [](/wiki?name=Test+Wiki+>+%26+%22+%27+%3c+Title&p) * [](/forumpost/481ab1f9) |
Added www/title-test.wiki.
> > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <title>Wiki Doc Title > & " ' < Test</title> Test of unusual characters in the title of Fossil-wiki formatted documents. The title should read: <big><b><verbatim> Wiki Doc Title > & " ' < Test </verbatim></b></big> See also: * [/doc/trunk/www/title-test.md] * [/wiki?name=Test+Wiki+>+%26+%22+%27+%3c+Title&p] * [/forumpost/481ab1f9] |